例如网购时 加入购物车、下单、支付,多个请求之间会有很长时间的间隔可能会过期回收,但是又需要让用户使用同一个数据库连接。
这样就需要维护一个TreadLocal的变量,来对应线程和连接的对应关系。
目的就是,为了多次操作数据库使用同一个连接。
JDK 1.2的版本中就提供java.lang.ThreadLocal,为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。通常用来在在多线程中管理共享数据库连接、Session等。
ThreadLocal用于保存某个线程共享变量,原因是在Java中,每一个线程对象中都有一个ThreadLocalMap<ThreadLocal, Object>,其key就是一个ThreadLocal,而Object即为该线程的共享变量。
而这个map是通过ThreadLocal的set和get方法操作的。对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。
- 在进行对象跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束。
- 线程间数据隔离。
- 进行事务操作,用于存储线程事务信息。
- 数据库连接,
Session
会话管理。1、ThreadLocal对象.get: 获取ThreadLocal中当前线程共享变量的值。
2、ThreadLocal对象.set: 设置ThreadLocal中当前线程共享变量的值。
3、ThreadLocal对象.remove: 移除ThreadLocal中当前线程共享变量的值。
在V1.0的版本基础上,我们将连接对象放在每个线程的ThreadLocal中,保证从头到尾当前线程操作的是同一连接对象。
代码实现:
package com.atguigu.senior.util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
/**
* JDBC工具类(V2.0):
* 1、维护一个连接池对象、维护了一个线程绑定变量的ThreadLocal对象
* 2、对外提供在ThreadLocal中获取连接的方法
* 3、对外提供回收连接的方法,回收过程中,将要回收的连接从ThreadLocal中移除!
* 注意:工具类仅对外提供共性的功能代码,所以方法均为静态方法!
* 注意:使用ThreadLocal就是为了一个线程在多次数据库操作过程中,使用的是同一个连接!
*/
public class JDBCUtilV2 {
//创建连接池引用,因为要提供给当前项目的全局使用,所以创建为静态的。
private static DataSource dataSource;
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
//在项目启动时,即创建连接池对象,赋值给dataSource
static {
try {
Properties properties = new Properties();
InputStream inputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");
properties.load(inputStream);
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//对外提供在连接池中获取连接的方法
public static Connection getConnection(){
try {
//在ThreadLocal中获取Connection、
Connection connection = threadLocal.get();
//threadLocal里没有存储Connection,也就是第一次获取
if (connection == null) {
//在连接池中获取一个连接,存储在threadLocal里。
connection = dataSource.getConnection();
threadLocal.set(connection);
}
return connection;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//对外提供回收连接的方法
public static void release(){
try {
Connection connection = threadLocal.get();
if(connection!=null){
//从threadLocal中移除当前已经存储的Connection对象
threadLocal.remove();
//如果开启了事务的手动提交,操作完毕后,归还给连接池之前,要将事务的自动提交改为true
connection.setAutoCommit(true);
//将Connection对象归还给连接池
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
推荐阅读: