Servlet/JSP MVC 项目事务处理ThreadLocal 实现 2 阶段提交与回滚1. 事务处理的必要性在传统的 Servlet/JSP MVC 项目中数据一致性是企业级应用的关键痛点。以一个简单的银行转账场景为例public void transfer(String fromActno, String toActno, double money) { // 查询转出账户 Account fromAct accountDao.selectByActno(fromActno); // 查询转入账户 Account toAct accountDao.selectByActno(toActno); // 修改内存中的余额 fromAct.setBalance(fromAct.getBalance() - money); toAct.setBalance(toAct.getBalance() money); // 更新数据库 accountDao.update(fromAct); accountDao.update(toAct); }这段代码存在严重的事务问题如果第二个 update 操作失败系统将处于不一致状态多线程并发操作时可能产生脏读、不可重复读等问题关键问题指标对比问题类型无事务处理有事务处理原子性❌ 操作可能部分成功✅ 全部成功或全部回滚一致性❌ 可能破坏业务规则✅ 始终符合业务规则隔离性❌ 并发问题严重✅ 隔离级别可控持久性❌ 故障可能导致数据丢失✅ 提交后永久保存2. ThreadLocal 事务管理原理ThreadLocal 是 Java 提供的线程局部变量机制它为每个使用该变量的线程提供独立的变量副本。在事务管理中我们可以利用这一特性实现连接绑定public class ConnectionUtils { private static ThreadLocalConnection tl new ThreadLocal(); public static Connection getConnection() { Connection conn tl.get(); if(conn null) { conn DataSourceUtils.getConnection(); tl.set(conn); } return conn; } public static void removeConnection() { tl.remove(); } }事务管理核心流程开启事务获取连接并设置为手动提交执行操作所有 DAO 使用同一连接提交/回滚根据执行结果决定释放资源关闭连接并移除 ThreadLocal注意必须确保连接在 finally 块中被释放否则会导致连接泄漏3. 二阶段提交实现方案3.1 事务管理器设计public class TransactionManager { public static void begin() throws SQLException { Connection conn ConnectionUtils.getConnection(); conn.setAutoCommit(false); } public static void commit() throws SQLException { Connection conn ConnectionUtils.getConnection(); conn.commit(); ConnectionUtils.removeConnection(); conn.close(); } public static void rollback() { try { Connection conn ConnectionUtils.getConnection(); conn.rollback(); ConnectionUtils.removeConnection(); conn.close(); } catch (SQLException e) { throw new RuntimeException(e); } } }3.2 服务层集成示例public class AccountService { public void transfer(String fromActno, String toActno, double money) { try { // 1. 开启事务 TransactionManager.begin(); // 2. 执行业务逻辑 Account fromAct accountDao.selectByActno(fromActno); Account toAct accountDao.selectByActno(toActno); fromAct.setBalance(fromAct.getBalance() - money); toAct.setBalance(toAct.getBalance() money); accountDao.update(fromAct); accountDao.update(toAct); // 3. 提交事务 TransactionManager.commit(); } catch (Exception e) { // 4. 回滚事务 TransactionManager.rollback(); throw e; } } }事务执行流程图开始 ├─ 开启事务(setAutoCommitfalse) ├─ 执行SQL操作 │ ├─ 操作1 │ └─ 操作2 ├─ 无异常? → 提交事务 └─ 有异常? → 回滚事务 结束4. 高级事务特性实现4.1 事务传播机制通过 ThreadLocal 栈实现嵌套事务public class TransactionManager { private static ThreadLocalStackConnection tl new ThreadLocal(); public static void begin() { StackConnection stack tl.get(); if(stack null) { stack new Stack(); tl.set(stack); } Connection conn DataSourceUtils.getConnection(); conn.setAutoCommit(false); stack.push(conn); } public static Connection getConnection() { StackConnection stack tl.get(); return stack.peek(); } }4.2 事务隔离级别控制public static void setIsolationLevel(int level) { Connection conn getConnection(); conn.setTransactionIsolation(level); }隔离级别对照表级别值脏读不可重复读幻读READ_UNCOMMITTED1可能可能可能READ_COMMITTED2不可能可能可能REPEATABLE_READ4不可能不可能可能SERIALIZABLE8不可能不可能不可能5. 性能优化建议连接池配置使用 Druid 等高性能连接池事务粒度控制避免长事务异常处理优化public void transfer(String fromActno, String toActno, double money) { boolean isNewTransaction false; try { if(ConnectionUtils.getConnection() null) { TransactionManager.begin(); isNewTransaction true; } // 业务逻辑 if(isNewTransaction) { TransactionManager.commit(); } } catch(Exception e) { if(isNewTransaction) { TransactionManager.rollback(); } throw new AppException(转账失败, e); } }在实际项目中这种基于 ThreadLocal 的事务管理方案虽然简单直接但对于复杂的分布式场景建议考虑使用成熟的框架如 Spring TransactionManager。