首页 > 其他分享 >Servlet25 - 事务管理

Servlet25 - 事务管理

时间:2023-01-25 11:00:30浏览次数:40  
标签:事务管理 回滚 ... DAO ThreadLocal Connection Servlet25 threadLocal

事务管理

什么是事务?

try{
    setAutoCommit(false);
    事务操作...
    commit();
}catch(Exception e){
    rollback();
}

目的是为了事务操作结果的一致性,事务操作中的所有操作必须同时成功,否则所有操作都回滚。

1 - DAO层进行事务管理

在每一个DAO中执行事务提交或回滚

2 - Service层进行事务管理

一个Service包含多个DAO,所有DAO的结果必须保持一致性

将整个 Service 视为事务操作,用 try-catch 语句包裹,可以将 try-catch 语句进一步优化,向前提取到 Filter 中

3 - Filter 中进行事务管理 -- 最终方案

filterChain.doFilter() 放行方法作为事务操作,在放行后的操作中,任意一处出错都回滚到放行前的状态

  • @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        try{
            TransactionManager.beginTrans();
            System.out.println("开启事务....");
            
            filterChain.doFilter(servletRequest, servletResponse);
            
            TransactionManager.commit();
            System.out.println("提交事务...");
        }catch (Exception e){
            e.printStackTrace();
            try {
                TransactionManager.rollback();
                System.out.println("回滚事务....");
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
    }
    

问题:提交或回滚实际上是提交或回滚 Connection 的内容,因此,如何使一个事物操作中的所有 DAO 都使用同一个连接 Connection ?

问题1 :使一次事物操作中的所有 DAO 使用同一个 Connection

ThreadLocal 线程本地变量
  • // 创建线程本地变量,存放 Connection 
    ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
    // 从线程本地变量中获取 Connection
    Connection conn = threadLocal.get();
    // 将 Connection 存入线程本地变量中
    threadLocal.set(conn);
    

一个 Service 中的每一个 DAO 都可以通过 ThreadLocal 获取同一个 Connection

封装 Connection 的操作方法到 ConnUtil 类中
  • public class ConnUtil { ...
    
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
    
    
    private static Connection createConn(){
        try {
            //1.加载驱动
            Class.forName(DRIVER);
            //2.通过驱动管理器获取连接对象
            return DriverManager.getConnection(URL, USER, PWD);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        
        return null ;
    }
    
    public static Connection getConn(){
        
        Connection conn = threadLocal.get();
        
        // 第一个 DAO 需要创建 Connection,并将 Connection 存入 ThreadLocal 中
        if(conn==null){
            conn =createConn();
            threadLocal.set(conn);
        }
    
        return threadLocal.get() ;
    }
    
    closeConn() ...
    

问题2 - 异常抛出

如果在 DAO 内部将异常捕获并处理,则出现的异常不会被外层 Filter 捕获,导致错误的结果没有回滚而是提交

因此,将内部的异常全部抛出,由 Filter 统一捕获并处理,然后回滚事务

当然,抛出的异常要分类,能够识别异常的来源,因此,需要自定义异常类,细分可能发生的异常,逐一抛出、捕获

public class DispatcherServletException extends RuntimeException {
    public DispatcherServletException(String msg){
        super(msg);
    }
}

public class DispatcherServlet{ 
    ...
    throw new DispatcherServletException("IOC容器获取失败!");
    ...
    throw new DispatcherServletException("DispatcherServlet出错了...");
    ...
}

标签:事务管理,回滚,...,DAO,ThreadLocal,Connection,Servlet25,threadLocal
From: https://www.cnblogs.com/Ashen-/p/17066750.html

相关文章