日期:2014-05-20  浏览次数:20818 次

这样多线程并发访问数据库会不会有问题?如果有如何解决?
本帖最后由 jilk89757 于 2013-05-21 18:03:23 编辑
最近有项目需要用多个数据库,我是将数据源放在一个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();
    }
多线程 并发 数据库

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

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

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

后面你获取session的地方,因为只是读,不涉及到修改,也不会存在问题。
------解决方案--------------------
多线程并发的获取连接,如果存在获取相同的连接,即通过你的dbMap缓存对象并发的通过同一key得到相同的connection的话,则可能出现问题。

你这个有点像一个针对多个数据库的缓存的连接池吧,其实可以设计更好一点,可以对每一个connection设计一个超时的时长,如果超过例如5分钟没有使用,则断开连接,并从dbMap中移除掉,具体实现可以参考DelayQueue.java
------解决方案--------------------
不好意思,没看清问题。如果是多个数据源只启动一次的话,而且数据源是只读的话,那段代码是没有问题的。

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

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

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

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

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