Spring 事务详解
一、Spring 事务简介
Spring 事务管理基于 AOP(面向切面编程)实现,通过 声明式事务(注解或 XML 配置)统一管理数据库操作,确保数据一致性。核心目标:保证多个数据库操作的原子性(要么全部成功,要么全部回滚)。
核心优势:
-
解耦业务代码与事务管理:通过注解配置,无需侵入业务逻辑。
-
支持多种事务管理器:如 JDBC、Hibernate、JPA 等。
-
灵活的事务传播行为:控制事务的边界和嵌套逻辑。
二、 案例:银行账户转账
需求:用户 A 向用户 B 转账,需保证扣款和存款操作同时成功或失败。
代码实现
(1) 业务层接口与实现类
public interface AccountService {void transfer(String fromUser, String toUser, int money);
}@Service
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;@Transactional // 开启事务管理@Overridepublic void transfer(String fromUser, String toUser, int money) {// 扣款accountDao.reduceMoney(fromUser, money);// 模拟异常(事务应回滚)// int i = 1 / 0; // 存款accountDao.addMoney(toUser, money);}
}
(2) 数据层(DAO)
@Repository
public class AccountDaoImpl implements AccountDao {@Autowiredprivate JdbcTemplate jdbcTemplate;public void reduceMoney(String user, int money) {String sql = "UPDATE account SET balance = balance - ? WHERE username = ?";jdbcTemplate.update(sql, money, user);}public void addMoney(String user, int money) {String sql = "UPDATE account SET balance = balance + ? WHERE username = ?";jdbcTemplate.update(sql, money, user);}
}
三、Spring 事务核心配置
步骤 1:启用事务管理
-
Spring Boot:默认已启用事务,无需额外配置。
-
非 Spring Boot:在配置类添加
@EnableTransactionManagement
。@Configuration @EnableTransactionManagement // 开启注解式事务驱动 public class AppConfig { ... }
步骤 2:配置事务管理器
-
Spring Boot:自动配置
DataSourceTransactionManager
。 -
手动配置:
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource); }
步骤 3:使用 @Transactional
注解
-
作用位置:类(所有方法生效)或方法。
-
关键属性:
-
propagation
:事务传播行为(默认REQUIRED
)。 -
isolation
:事务隔离级别(默认DEFAULT
,跟随数据库)。 -
rollbackFor
:指定触发回滚的异常类型。 -
timeout
:事务超时时间(秒)。
-
四、Spring 事务角色
角色 | 说明 |
---|---|
事务管理器 | PlatformTransactionManager 接口的实现类(如 DataSourceTransactionManager )。 |
事务定义 | 通过 @Transactional 注解或 XML 配置定义事务属性(传播行为、隔离级别等)。 |
事务状态 | 事务的运行时状态(如是否是新事务、是否回滚)。 |
五、Spring 事务属性
属性 | 说明 | 常用值 |
---|---|---|
propagation | 事务传播行为(控制事务边界) | REQUIRED (默认)、REQUIRES_NEW 、NESTED 、SUPPORTS 等。 |
isolation | 事务隔离级别(解决并发问题) | DEFAULT 、READ_COMMITTED 、READ_UNCOMMITTED 、REPEATABLE_READ 等。 |
timeout | 事务超时时间(秒),超时自动回滚。 | 默认 -1(无超时)。 |
readOnly | 是否只读事务(优化数据库性能)。 | true 或 false (默认)。 |
rollbackFor | 触发回滚的异常类型(默认仅回滚 RuntimeException )。 | 如 rollbackFor = Exception.class 。 |
noRollbackFor | 不触发回滚的异常类型。 | 如 noRollbackFor = NullPointerException.class 。 |
六、 事务传播行为(Propagation)
控制事务方法之间如何相互影响,常见行为:
传播行为 | 说明 |
---|---|
REQUIRED | 如果当前存在事务,则加入该事务;否则新建一个事务(默认行为)。 |
REQUIRES_NEW | 无论当前是否存在事务,都新建一个事务,挂起当前事务(独立提交)。 |
SUPPORTS | 如果当前存在事务,则加入;否则以非事务方式执行。 |
NESTED | 如果当前存在事务,则嵌套在子事务中执行(可部分回滚)。 |
七、案例:转账业务追加日志
需求:在转账操作后记录日志,且日志记录必须成功(即使转账失败也要记录)。
代码实现
@Service
public class LogService {@Autowiredprivate LogDao logDao;// 使用 REQUIRES_NEW 传播行为:独立事务@Transactional(propagation = Propagation.REQUIRES_NEW)public void addLog(String logInfo) {logDao.insertLog(logInfo);// 即使转账失败,日志也会提交}
}@Service
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;@Autowiredprivate LogService logService;@Transactional@Overridepublic void transfer(String fromUser, String toUser, int money) {accountDao.reduceMoney(fromUser, money);accountDao.addMoney(toUser, money);// 记录日志(独立事务)logService.addLog("转账操作:" + fromUser + " 向 " + toUser + " 转账 " + money);}
}
关键点:
-
日志方法
addLog
使用REQUIRES_NEW
,确保日志事务独立提交。 -
即使转账事务回滚,日志事务仍会提交。
八、事务配置示例
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED,timeout = 30,rollbackFor = {SQLException.class, IOException.class}
)
public void businessMethod() { ... }
九、 常见问题
-
事务不生效:
-
检查是否启用事务管理(
@EnableTransactionManagement
)。 -
确保
@Transactional
注解应用在public
方法上。 -
确认异常类型是否触发回滚(默认仅回滚
RuntimeException
和Error
)。
-
-
事务传播行为错误:
-
嵌套事务中错误使用
REQUIRES_NEW
可能导致事务过多,影响性能。
-
十、总结
-
核心注解:
@EnableTransactionManagement
(启用事务)、@Transactional
(定义事务属性)。 -
事务传播行为:根据业务需求选择合适的行为(如
REQUIRED
或REQUIRES_NEW
)。 -
事务管理本质:基于 AOP 动态代理实现,通过事务管理器控制数据库连接。
进一步实践:结合具体业务场景测试不同传播行为和隔离级别,深入理解事务的边界控制!