您的位置:首页 > 其它

事务处理中的ThreadLocal的使用

2015-09-10 20:46 281 查看

事务处理中的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容器中移除对应当前线程的链接)
        }
    }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: