Servlet25 - 事务管理
事务管理
什么是事务?
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出错了...");
...
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析