这样多线程并发访问数据库会不会有问题?如果有如何解决?

时间:2021-11-26 21:45:26
最近有项目需要用多个数据库,我是将数据源放在一个map中保存的,每次应用获取连接时都去map中先拿到数据源,再获取连接。如果多线程并发取连接会不会有问题,求大神指点!说明:ComboPooledDataSource是c3p0一个简单连接池的应用

保存数据源

LinkedHashMap dbMap = new  LinkedHashMap();
        ComboPooledDataSource instance1 = new ComboPooledDataSource();
        instance1.set...(..);//设置数据源参数
        ComboPooledDataSource instance2 = new ComboPooledDataSource();
        instance1.set...(..);//设置数据源参数
        
        dbMap.put("instance1", instance1);//用dbMap保存多个数据源
        dbMap.put("instance2", instance2);

获取数据库连接

public Connection getConnection(String dataSourceName) throws SQLException {
            return dbMap.get(dataSourceName).getConnection();
    }

12 个解决方案

#1



理论上是ok的,最好还是能性能测试一把。

#2


来我的博客下个开源项目,里面有用多数据源的处理方案

#3


不能这样做的,ComboPooledDataSource 全局只要一个实例就可以了,没有必要每访问一次数据库就创建一个 ComboPooledDataSource 对象,这样太吓人了!

对于数据库来说都是支持并发访问的,但是从 ComboPooledDataSource 中获得的 Connection 连接对象不是线程安全的,一个 Connection 只能在一个线程中,或者局部变量中使用,不得在多个线程*享一个 Connection。

#4


引用 3 楼 bao110908 的回复:
不能这样做的,ComboPooledDataSource 全局只要一个实例就可以了,没有必要每访问一次数据库就创建一个 ComboPooledDataSource 对象,这样太吓人了!

对于数据库来说都是支持并发访问的,但是从 ComboPooledDataSource 中获得的 Connection 连接对象不是线程安全的,一个 Connection 只能在一个线程中,或者局部变量中使用,不得在多个线程*享一个 Connection。

不同意这个说法。楼主本来就是多个数据库,对应多个数据源。
dbMap.put(key, value)的时候,因为map里key的唯一性,不会存在并发问题。
这里应该是程序启动时执行一次就行了。

后面你获取session的地方,因为只是读,不涉及到修改,也不会存在问题。

#5


应该没问题。

#6


引用 3 楼 bao110908 的回复:
不能这样做的,ComboPooledDataSource 全局只要一个实例就可以了,没有必要每访问一次数据库就创建一个 ComboPooledDataSource 对象,这样太吓人了!

对于数据库来说都是支持并发访问的,但是从 ComboPooledDataSource 中获得的 Connection 连接对象不是线程安全的,一个 Connection 只能在一个线程中,或者局部变量中使用,不得在多个线程*享一个 Connection。


并不是访问一次数据库就创建一次,只有在最初加载配置时将所有配置中的数据库创建ComboPooledDataSource并保存在dbMap中,如果有请求过来根据数据库名称获取ComboPooledDataSource; “ 但是从 ComboPooledDataSource 中获得的 Connection 连接对象不是线程安全的” 这个是有相关资料吗,我也比较担心这点

#7


引用 4 楼 u010255083 的回复:
Quote: 引用 3 楼 bao110908 的回复:

不能这样做的,ComboPooledDataSource 全局只要一个实例就可以了,没有必要每访问一次数据库就创建一个 ComboPooledDataSource 对象,这样太吓人了!

对于数据库来说都是支持并发访问的,但是从 ComboPooledDataSource 中获得的 Connection 连接对象不是线程安全的,一个 Connection 只能在一个线程中,或者局部变量中使用,不得在多个线程*享一个 Connection。

不同意这个说法。楼主本来就是多个数据库,对应多个数据源。
dbMap.put(key, value)的时候,因为map里key的唯一性,不会存在并发问题。
这里应该是程序启动时执行一次就行了。

后面你获取session的地方,因为只是读,不涉及到修改,也不会存在问题。


非常感谢解释,明白了,map只有在加载配置时修改,其他时候只是多线程读,所以取ComboDataSource应该是没问题的,我想关于C3P0自己封装好ComboDataSource获取Connection应该是线程安全的 

#8


引用 4 楼 u010255083 的回复:
Quote: 引用 3 楼 bao110908 的回复:

不能这样做的,ComboPooledDataSource 全局只要一个实例就可以了,没有必要每访问一次数据库就创建一个 ComboPooledDataSource 对象,这样太吓人了!

对于数据库来说都是支持并发访问的,但是从 ComboPooledDataSource 中获得的 Connection 连接对象不是线程安全的,一个 Connection 只能在一个线程中,或者局部变量中使用,不得在多个线程*享一个 Connection。

不同意这个说法。楼主本来就是多个数据库,对应多个数据源。
dbMap.put(key, value)的时候,因为map里key的唯一性,不会存在并发问题。
这里应该是程序启动时执行一次就行了。

后面你获取session的地方,因为只是读,不涉及到修改,也不会存在问题。


如果中途改一个数据库配置,需要更新ComboDataSource呢

#9


多线程并发的获取连接,如果存在获取相同的连接,即通过你的dbMap缓存对象并发的通过同一key得到相同的connection的话,则可能出现问题。

你这个有点像一个针对多个数据库的缓存的连接池吧,其实可以设计更好一点,可以对每一个connection设计一个超时的时长,如果超过例如5分钟没有使用,则断开连接,并从dbMap中移除掉,具体实现可以参考DelayQueue.java

#10


dbMap中存的是ComboPooledDataSource(有连接池的数据源)对象,每次收到请求过来后,会先从dbMap中拿到数据库对象,再通过数据源对象获取连接; 


ComboPooledDataSource 中有个设置连接检出时间,超时则回收 setCheckoutTimeout(checkoutTimeout)

#11


不好意思,没看清问题。如果是多个数据源只启动一次的话,而且数据源是只读的话,那段代码是没有问题的。

-------------------------------------------------------------------
我想关于C3P0自己封装好ComboDataSource获取Connection应该是线程安全的
-------------------------------------------------------------------
可以很明确地告诉你,Connection 不是线程安全的。JDBC 规范并没有强制要求 Connection 必须是线程安全的,因此 JDBC 驱动厂商不会将其实现为线程安全的。

C3P0 的数据源只是个连接池,只是在 JDBC 的 Connection 上做过一层包装而已,并不会去更改原始 Connection 的行为。

一般来说,基于 TCP 通信的实现的连接池都不会是线程安全的,JDBC 连接池也不例外。

你这个还有个问题,多个数据源用起来其实没有你想像得那么简单,最主要的问题在于多数据源的事务处理问题上。在 J2SE 环境中没法处理多数据源的分布式事务,一般只有在 J2EE 环境中使用 JTA 才能处理分布式事务,当然了,多数据源的分布式事务处理的性能也是很差的。

在 J2SE 环境中可以看一下 jOTM, jencks, SimpleJTA, atomikos 等框架。

#12


引用 11 楼 bao110908 的回复:
不好意思,没看清问题。如果是多个数据源只启动一次的话,而且数据源是只读的话,那段代码是没有问题的。

-------------------------------------------------------------------
我想关于C3P0自己封装好ComboDataSource获取Connection应该是线程安全的
-------------------------------------------------------------------
可以很明确地告诉你,Connection 不是线程安全的。JDBC 规范并没有强制要求 Connection 必须是线程安全的,因此 JDBC 驱动厂商不会将其实现为线程安全的。

C3P0 的数据源只是个连接池,只是在 JDBC 的 Connection 上做过一层包装而已,并不会去更改原始 Connection 的行为。

一般来说,基于 TCP 通信的实现的连接池都不会是线程安全的,JDBC 连接池也不例外。

你这个还有个问题,多个数据源用起来其实没有你想像得那么简单,最主要的问题在于多数据源的事务处理问题上。在 J2SE 环境中没法处理多数据源的分布式事务,一般只有在 J2EE 环境中使用 JTA 才能处理分布式事务,当然了,多数据源的分布式事务处理的性能也是很差的。

在 J2SE 环境中可以看一下 jOTM, jencks, SimpleJTA, atomikos 等框架。


弱弱的问一句,如果判断或验证是否线程安全

#1



理论上是ok的,最好还是能性能测试一把。

#2


来我的博客下个开源项目,里面有用多数据源的处理方案

#3


不能这样做的,ComboPooledDataSource 全局只要一个实例就可以了,没有必要每访问一次数据库就创建一个 ComboPooledDataSource 对象,这样太吓人了!

对于数据库来说都是支持并发访问的,但是从 ComboPooledDataSource 中获得的 Connection 连接对象不是线程安全的,一个 Connection 只能在一个线程中,或者局部变量中使用,不得在多个线程*享一个 Connection。

#4


引用 3 楼 bao110908 的回复:
不能这样做的,ComboPooledDataSource 全局只要一个实例就可以了,没有必要每访问一次数据库就创建一个 ComboPooledDataSource 对象,这样太吓人了!

对于数据库来说都是支持并发访问的,但是从 ComboPooledDataSource 中获得的 Connection 连接对象不是线程安全的,一个 Connection 只能在一个线程中,或者局部变量中使用,不得在多个线程*享一个 Connection。

不同意这个说法。楼主本来就是多个数据库,对应多个数据源。
dbMap.put(key, value)的时候,因为map里key的唯一性,不会存在并发问题。
这里应该是程序启动时执行一次就行了。

后面你获取session的地方,因为只是读,不涉及到修改,也不会存在问题。

#5


应该没问题。

#6


引用 3 楼 bao110908 的回复:
不能这样做的,ComboPooledDataSource 全局只要一个实例就可以了,没有必要每访问一次数据库就创建一个 ComboPooledDataSource 对象,这样太吓人了!

对于数据库来说都是支持并发访问的,但是从 ComboPooledDataSource 中获得的 Connection 连接对象不是线程安全的,一个 Connection 只能在一个线程中,或者局部变量中使用,不得在多个线程*享一个 Connection。


并不是访问一次数据库就创建一次,只有在最初加载配置时将所有配置中的数据库创建ComboPooledDataSource并保存在dbMap中,如果有请求过来根据数据库名称获取ComboPooledDataSource; “ 但是从 ComboPooledDataSource 中获得的 Connection 连接对象不是线程安全的” 这个是有相关资料吗,我也比较担心这点

#7


引用 4 楼 u010255083 的回复:
Quote: 引用 3 楼 bao110908 的回复:

不能这样做的,ComboPooledDataSource 全局只要一个实例就可以了,没有必要每访问一次数据库就创建一个 ComboPooledDataSource 对象,这样太吓人了!

对于数据库来说都是支持并发访问的,但是从 ComboPooledDataSource 中获得的 Connection 连接对象不是线程安全的,一个 Connection 只能在一个线程中,或者局部变量中使用,不得在多个线程*享一个 Connection。

不同意这个说法。楼主本来就是多个数据库,对应多个数据源。
dbMap.put(key, value)的时候,因为map里key的唯一性,不会存在并发问题。
这里应该是程序启动时执行一次就行了。

后面你获取session的地方,因为只是读,不涉及到修改,也不会存在问题。


非常感谢解释,明白了,map只有在加载配置时修改,其他时候只是多线程读,所以取ComboDataSource应该是没问题的,我想关于C3P0自己封装好ComboDataSource获取Connection应该是线程安全的 

#8


引用 4 楼 u010255083 的回复:
Quote: 引用 3 楼 bao110908 的回复:

不能这样做的,ComboPooledDataSource 全局只要一个实例就可以了,没有必要每访问一次数据库就创建一个 ComboPooledDataSource 对象,这样太吓人了!

对于数据库来说都是支持并发访问的,但是从 ComboPooledDataSource 中获得的 Connection 连接对象不是线程安全的,一个 Connection 只能在一个线程中,或者局部变量中使用,不得在多个线程*享一个 Connection。

不同意这个说法。楼主本来就是多个数据库,对应多个数据源。
dbMap.put(key, value)的时候,因为map里key的唯一性,不会存在并发问题。
这里应该是程序启动时执行一次就行了。

后面你获取session的地方,因为只是读,不涉及到修改,也不会存在问题。


如果中途改一个数据库配置,需要更新ComboDataSource呢

#9


多线程并发的获取连接,如果存在获取相同的连接,即通过你的dbMap缓存对象并发的通过同一key得到相同的connection的话,则可能出现问题。

你这个有点像一个针对多个数据库的缓存的连接池吧,其实可以设计更好一点,可以对每一个connection设计一个超时的时长,如果超过例如5分钟没有使用,则断开连接,并从dbMap中移除掉,具体实现可以参考DelayQueue.java

#10


dbMap中存的是ComboPooledDataSource(有连接池的数据源)对象,每次收到请求过来后,会先从dbMap中拿到数据库对象,再通过数据源对象获取连接; 


ComboPooledDataSource 中有个设置连接检出时间,超时则回收 setCheckoutTimeout(checkoutTimeout)

#11


不好意思,没看清问题。如果是多个数据源只启动一次的话,而且数据源是只读的话,那段代码是没有问题的。

-------------------------------------------------------------------
我想关于C3P0自己封装好ComboDataSource获取Connection应该是线程安全的
-------------------------------------------------------------------
可以很明确地告诉你,Connection 不是线程安全的。JDBC 规范并没有强制要求 Connection 必须是线程安全的,因此 JDBC 驱动厂商不会将其实现为线程安全的。

C3P0 的数据源只是个连接池,只是在 JDBC 的 Connection 上做过一层包装而已,并不会去更改原始 Connection 的行为。

一般来说,基于 TCP 通信的实现的连接池都不会是线程安全的,JDBC 连接池也不例外。

你这个还有个问题,多个数据源用起来其实没有你想像得那么简单,最主要的问题在于多数据源的事务处理问题上。在 J2SE 环境中没法处理多数据源的分布式事务,一般只有在 J2EE 环境中使用 JTA 才能处理分布式事务,当然了,多数据源的分布式事务处理的性能也是很差的。

在 J2SE 环境中可以看一下 jOTM, jencks, SimpleJTA, atomikos 等框架。

#12


引用 11 楼 bao110908 的回复:
不好意思,没看清问题。如果是多个数据源只启动一次的话,而且数据源是只读的话,那段代码是没有问题的。

-------------------------------------------------------------------
我想关于C3P0自己封装好ComboDataSource获取Connection应该是线程安全的
-------------------------------------------------------------------
可以很明确地告诉你,Connection 不是线程安全的。JDBC 规范并没有强制要求 Connection 必须是线程安全的,因此 JDBC 驱动厂商不会将其实现为线程安全的。

C3P0 的数据源只是个连接池,只是在 JDBC 的 Connection 上做过一层包装而已,并不会去更改原始 Connection 的行为。

一般来说,基于 TCP 通信的实现的连接池都不会是线程安全的,JDBC 连接池也不例外。

你这个还有个问题,多个数据源用起来其实没有你想像得那么简单,最主要的问题在于多数据源的事务处理问题上。在 J2SE 环境中没法处理多数据源的分布式事务,一般只有在 J2EE 环境中使用 JTA 才能处理分布式事务,当然了,多数据源的分布式事务处理的性能也是很差的。

在 J2SE 环境中可以看一下 jOTM, jencks, SimpleJTA, atomikos 等框架。


弱弱的问一句,如果判断或验证是否线程安全