ThreadLocal类的作用
ThreadLocal 它可以给当前线程关联一个数据(可以是普通变量,可以是对象,也可以是数组,集合)
ThreadLocal 的作用,它可以解决多线程的数据安全问题。
ThreadLocal 的特点:
1、ThreadLocal 可以为当前线程关联一个数据。(它可以像 Map 一样存取数据,key 为当前线程)
2、每一个 ThreadLocal 对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个 ThreadLocal 对象实例。
3、每个 ThreadLocal 对象实例定义的时候,一般都是 static 类型
4、ThreadLocal 中保存数据,在线程销毁后。会由 JVM 虚拟自动释放。
前提:客户端发起一次请求进入Filter然后后进入Servlet然后调用Service层然后调用Dao层,这些操作都在同一线程完成,所以可以给这个线程绑定一个数据库连接对象
1.首先修改JDBC工具类绑定ThreadLocal
public static Connection getConnection(){
Connection connection =ThreadConns.get();
if (connection==null){//如果线程数据获取的连接为空
try {
connection=druidDataSource.getConnection();//从数据连接池获取一个连接
connection.setAutoCommit(false);//关闭自动提交
ThreadConns.set(connection);//设置这个连接到当前执行的线程
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
return connection;
}
public static void commitAndClose(){
Connection connection = ThreadConns.get();
if (connection!=null){//如果当前线程获取的连接不为null
try {
connection.commit();//提交数据库操做事务
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
connection.close();//关闭连接
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
ThreadConns.remove();//一定要remove当前线程的connection数据库连接对象,否则会出错,因为Tomcat底层使用了线程池技术
}
public static void rollbackAndClose(){
Connection connection = ThreadConns.get();
if (connection!=null){//如果当前线程获取的连接不为null
try {
connection.rollback();//提交数据库操做事务
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
connection.close();//关闭连接
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
ThreadConns.remove();//一定要remove当前线程的connection数据库连接对象,否则会出错,因为Tomcat底层使用了线程池技术
}
2.有关于BaseDao数据更新的操作都要手动捕获抛出异常
public Object queryForSingleObject(String sql,Object... args){
Connection connection= JdbcUtils.getConnection();
try {
return queryRunner.query(connection,sql,new ScalarHandler(),args);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);//把异常通通抛出给最后在filter统一捕获做事务管理
}
}
public <T> T queryForOne(Class<T> clazz,String sql,Object... args){
Connection connection= JdbcUtils.getConnection();
try {
return queryRunner.query(connection, sql, new BeanHandler<>(clazz), args);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);//把异常通通抛出给最后在filter统一捕获做事务管理
}
}
3.service服务层和BaseServlet的异常也要抛出,这里只列出BaseServlet
public class BaseServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String action=req.getParameter("action");
try {
Method declaredMethod = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
declaredMethod.invoke(this,req,resp);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);//把异常通通抛出给最后在filter统一捕获做事务管理
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
}
4.TransactionFilter拦截请求,并捕获异常进行事务管理
public class TransactionFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
try {
filterChain.doFilter(servletRequest,servletResponse);
JdbcUtils.commitAndClose();//没有异常则提交事务并关闭连接
} catch (Exception e) {
JdbcUtils.rollbackAndClose();//有异常则回滚并关闭连接
e.printStackTrace();
}
}
@Override
public void destroy() {
}
}