Connection实例是线程安全的吗

关于JDBC中关于Connection的两个疑问:

 

1.Connection实例是线程安全的吗?

    即一个connection实例,在多线程环境中是否可以确保数据操作是安全的?

private static Connection connection;  

    上述代码,设计会不会有问题? 一个Connection实例,即对应底层一个TCP链接,有些开发者可能考虑到"性能",就将代码写成上述样式,最终一个application中所有的DB操作,使用一个connection.确实减少了与DB的TCP链接个数,但是这真的安全吗??真的提升了性能了吗??

    1) 似乎一个初学者都不会这些写,因为没有sample是这么展示的.但是往往会在每个方法调用时都新建connection,然后close();

    2) 当一个开发者考虑到性能的时候,可能会写出上面的代码..

 

    Connection不是线程安全的,它在多线程环境中使用时,会导致数据操作的错乱,特别是有事务的情况.connection.commit()方法就是提交事务,你可以想象,在多线程环境中,线程A开启了事务,然后线程B却意外的commit,这该是个多么纠结的情况.

    如果在没有事务的情况下,且仅仅是简单的SQL Select操作,似乎在不会出现数据错乱,一切看起来比较安全.但是这并非意味着提升了性能,JDBC的各种实现中,connection的各种操作都进行了同步:

##PreparedStatement  
public int executeUpdate(){  
    synchronized(connection){  
        //do      
    }  
}  

同时只有当DB操作完成之后,方法调用才会返回. 尽管connection实例的个数唯一,但是在并发环境中,connection实例上锁竞争是必然的,反而没有提升性能(并发量).通常情况下,一个Connection实例只会在一个线程中使用,使用完之后close().

    TCP链接的创建开支是昂贵的,当然DB server所能承载的TCP并发连接数也是有限制的.因此每次调用都创建一个Connection,这是不现实的;所以才有了数据库连接池的出现.

    数据库连接池中保持了一定数量的connection实例,当需要DB操作的时候"borrow"一个出来,使用结束之后"return"到连接池中,多线程环境中,连接池中的connection实例交替性的被多个线程使用.

 

2. 在使用dataSourcePool的情况下,一个线程中所有的DB操作使用的是同一个connection吗??

    比如线程A,依次调用了2个方法,每个方法都进行了一次select操作,那么这两个select操作是使用同一个connection吗?

    第一感觉就是: dataSourcePool本身是否使用了threadLocal来保存线程与connection实例的引用关系;如果使用了threadLocal,那么一个线程多次从pool中获取是同一个connection,直到线程消亡或者调用向pool归还资源..

    如果在spring环境中(或者其他ORM矿建中),这个问题需要分2种情况:事务与非事务.

    在非事务场景下,一切都很简单,每一次调用,都是从pool中取出一个connection实例,调用完毕之后归还资源,因此多次调用,应该是不同的connection实例.

 

public List<Object> select(String sql){  
    Connection connection = pool.getConnection();  
    //do  
    pool.release(connection);//归还资源  
}  

    在使用事务的场景下,情况就有所不同,开启一个新事务的同时,就会冲pool中获取一个connection实例,并将transaction和connection互为绑定,即此transaction中只会使用此connection,此connection此时只会在一个transaction中使用;因此,在此事务中,无论操作了多少次DB,事实上只会是一个connection实例,直到事务提交或者回滚,当事务提交或者回滚时,将会解除transaction与connection的绑定关系,同时将connection归还到pool中.

//开启事务  
public TransactionHolder transaction(){  
    Connection connection = pool.getConnection();  
    connection.setAutoCommit(false);  
    return new TransactionHolder(connection);  
}  
  
//执行sql  
public boolean insert(String sql,TransactionHolder holder){  
    Connection connection = holder.getConnection();  
    //do  
    try{  
        //doInsert  
        return true;  
    }catch(Exception e){  
        holder.setRollback(true);  
    }  
    return false;  
}  
  
//提交事务  
public void commit(TransactionHolder holder){  
    Connection connection = holder.getConnection();  
    connection.commit();  
    holder.unbind();//解除绑定  
    pool.release(connection);//归还资源   
}  

    在有事务的情况上,伪代码可能就像上述例子.对于跨DB分布式事务,可能更加的复杂. 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的Java多线程事务的示例: ``` public class TransactionThread extends Thread { private Connection conn; private String sql; public TransactionThread(Connection conn, String sql) { this.conn = conn; this.sql = sql; } public void run() { try { // 关闭自动提交,开启事务 conn.setAutoCommit(false); // 执行SQL语句 Statement stmt = conn.createStatement(); stmt.executeUpdate(sql); // 提交事务 conn.commit(); // 关闭连接 stmt.close(); conn.close(); } catch (SQLException e) { try { // 出现异常,回滚事务 conn.rollback(); // 关闭连接 conn.close(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); } } public static void main(String[] args) { // 获取数据库连接池 DataSource dataSource = getDataSource(); // 创建多个线程进行事务操作 TransactionThread thread1 = new TransactionThread(dataSource.getConnection(), "INSERT INTO table1 (col1, col2) VALUES ('value1', 'value2')"); TransactionThread thread2 = new TransactionThread(dataSource.getConnection(), "UPDATE table2 SET col1='value1' WHERE col2='value2'"); thread1.start(); thread2.start(); } } ``` 该示例中,我们创建了一个TransactionThread类,用来执行一个SQL语句,并在多线程环境下进行事务管理。在run方法中,我们首先关闭自动提交,开启事务;然后执行SQL语句;如果执行过程中出现异常,我们回滚事务;否则提交事务。在main方法中,我们创建了两个TransactionThread对象,分别执行不同的SQL语句,以模拟多线程环境下的事务操作。需要注意的是,在实际应用中,我们应该使用专业的事务管理框架,如Spring的声明式事务管理,来进行事务操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值