ThreadLocal的基本理解
Threadlocal很多地方都叫线程本地变量,也有很多地方叫线程本地存储,个人理解在业务上方法调用方法时都是在单线程中进行操作,在进行访问数据库时牵扯到事务操作时,因为要求要做到事务的start transaction()和commit()操作都需要同一个connection来执行,而恰巧我们的connection是从线程池中调用的。因此,我们不能保证我们进行事务开启和提交时都是用的相同的connection对象,在MVC三层架构中,一个层的方法调用另一个层的方法,难免会产生错误,比如数据库的脏读、不一致读等等,因此这里有两个解决办法。
①将connection对象作为参数传递给方法,这样就可以保证每次调用的connection对象都是一致的,但是个人觉得,这样就违背了面向对象的封装理念,同时代码也显得很臃肿,下面给出另一种解决办法,也就是用到了我们的ThreadLocal。
②private static ThreadLocal tl = new ThreadLocal(); ThreadLoacl是一个类似Map的数据结构,key是当前的线程名称,value是当前的connection对象。由于ThreadLocal本身实现了自动封装,因为当前线程名称是固定的,所以对应的一个key仅有一个connection对象与之对应。 我们创建一个connection集合,因为我们在一次方法之间的调用时,是单线程工作,我们将数据库事务的开启、提交、终止等操作都封装到工具类中,由工类负责事务的开启等。每次进行事务操作时,都从本地的ThreadLocal中寻connection对象,这样一来就可以保证每次进行数据库读写操作时,都是固定的一个connection对象。
public static void startTransaction() throws SQLException {
Connection currentonnection = getCurrentonnection();
currentonnection.setAutoCommit(false);
}
// 获得当前线程上绑定的conn
public static Connection getCurrentonnection() throws SQLException {
// 从TheradLocal寻找当前线程是否有对应Connection
Connection connection = tl.get();
if (connection == null) {
// 获得一个新的connection资源
connection = getConnection();
// 讲connection资源绑定到threadlocal(map)上
tl.set(connection);
}
return connection;
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
// 回滚事务
public static void rollback() throws SQLException {
// TODO Auto-generated method stub
getCurrentonnection().rollback();
}
public static void commit() throws SQLException {
// TODO Auto-generated method stub
Connection currentonnection = getCurrentonnection();
currentonnection.commit();
tl.remove();
currentonnection.close();
}