private static ThreadLocal TL = new ThreadLocal();
所谓的ThreadLocal就是本地线程。API文档中给出的定义是:该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。
ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
计算机对于线程的执行是抢占式策略,谁能抢到谁先执行,因此并不能控制线程的执行顺序。因此在一些静态资源上会进行共享,产生线程不安全问题。
而对于数据库的Transaction,可以用ThreadLocal进行控制,
比如下面的代码
//本地线程变量,用于事务控制,为每一个进程创建一个connection对象
private static ThreadLocal TL = new ThreadLocal();
//创建链接对象
public static Connection getConnection () throws SQLException{
//尝试从本地的线程中找到connection
Connection conn = null;
conn = TL.get();
//如果拿不到或者拿到的不可用
if(conn == null || conn.isClosed()) {
//重新创建一个connection
conn = DriverManager.getConnection(url, user, password);
//存储到TL
TL.set(conn);
}
return conn;
}
同时也可以做到将自动提交关闭,进行手动提交
public static void startTransaction() {
try {
Connection conn = getConnection();
if (conn != null)
conn.setAutoCommit(false);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static void commit() {
try {
Connection conn = getConnection();
if (conn != null) {
conn.commit();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
API文档中写到
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
但是建议要自行从ThreadLocal中将自己添加的进程移除
public static void close(ResultSet rs, Statement stmt, Connection conn) {
close(rs);
close(stmt);
close(conn);
TL.remove();
}
public static void close(ResultSet rs) {
try {
if (rs != null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void close(Statement stmt) {
try {
if (stmt != null)
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void close(Connection conn) {
try {
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void close() {
try {
close(getConnection());
} catch (SQLException e) {
e.printStackTrace();
}
}
~~~