事务处理中的ThreadLocal的使用

事务处理中的ThreadLocal的使用

简单的理解ThreadLocal

所谓ThreadLocal,简单一点想,就是一个全局的Map,Map的key是线程对象,value是你要保存的对象
进入某个线程后,就可以从map中取得之前存储的相应线程关联的对象。
NT:ThreadLocal并不是一个Map,但用Map来理解是没有问题的

在事务中使用ThreadLocal

确保所有的sql语句都在同一个开启了事务的链接上执行,这时候就可以使用ThreadLocal来解决这个问题。
解决思路:
这里写图片描述

代码实现:

//绑定开启了链接的connection到ThreadLocal的JdbcUtils工具类
public class JdbcUtils {
    private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();  //map


    public static void startTransaction(){
        try{
            //得到当前线程上绑定连接开启事务
            Connection conn = tl.get();
            if(conn==null){  //代表线程上没有绑定连接
                conn = ds.getConnection();    //ds 代表数据源, 这里省略他的代码
                tl.set(conn);
            }
            conn.setAutoCommit(false);
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    public static void commitTransaction(){
        try{
            Connection conn = tl.get();
            if(conn!=null){
                conn.commit();
            }
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static Connection getConnection() throws SQLException{
        try{
            //得到当前线程上绑定的连接
            Connection conn = tl.get();
            if(conn==null){  //代表线程上没有绑定连接
                conn = ds.getConnection();
                tl.set(conn);
            }
            return conn;
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


}



//在服务层用上ThreadLocal的事务管理
public void transfer2(int sourceid,int targetid,double money) throws SQLException{
    try{
        JdbcUtils.startTransaction();
        AccountDao dao = new AccountDao();
        Account a = dao.find(sourceid);   //select
        Account b = dao.find(targetid);   //select
        a.setMoney(a.getMoney()-money);  
        b.setMoney(b.getMoney()+money);   
        dao.update(a); //update
        dao.update(b);//update
        JdbcUtils.commitTransaction();
    }finally{
        JdbcUtils.closeConnection();
    }
}
}

//持久层,获取绑定在当前线程上的connection,进行操作

public Account find(int id){
        try{
            QueryRunner runner = new QueryRunner();
            String sql = "select * from account where id=?";
            return (Account) runner.query(JdbcUtils.getConnection(),sql, id, new BeanHandler(Account.class));
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

使用ThreadLocal应该注意的问题

在上面的代码中将ThreadLocal对象做成了静态
private static ThreadLocal tl = new ThreadLocal(); //map

因此,每次开启一条线程,ThreadLocal都会有一个Connection加进来,所以,我们要记得将这些Connection移除,不然
这个ThreadLocal静态对象会越变越大,最后导致程序挂掉!!!!!!

-> 即,在关闭链接是,把变量移除

    public static void closeConnection(){
        try{
            Connection conn = tl.get();
            if(conn!=null){
                conn.close();
            }
        }catch (Exception e) {
            throw new RuntimeException(e);
        }finally{
            tl.remove();   //千万注意,解除当前线程上绑定的链接(从threadlocal容器中移除对应当前线程的链接)
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值