SpringBoot中@Transactional注解的实际应用场景及示例解析
关于@Transactional注解的全面解析:概念、场景与示例
一、核心概念
@Transactional是Spring框架提供的声明式事务管理注解,本质是通过AOP代理自动完成事务的开启、提交、回滚流程,不用手动编写JDBC事务的conn.setAutoCommit(false)、commit()、rollback()这类代码。
事务的核心价值是保证数据一致性:一组关联的数据库操作,要么全部执行成功,要么全部回滚到操作前的状态,绝对不允许出现“部分成功、部分失败”的中间状态。
二、实际业务应用场景
以下是日常开发中最常见的使用场景:
- 资金转账:用户A向用户B转账时,需要同时执行“扣减A的余额”和“增加B的余额”两个操作。如果其中任何一步失败,必须把已经执行的操作回滚,避免出现钱凭空消失或多出来的情况。
- 订单与库存联动:创建订单时,要同步扣减对应商品的库存。如果订单创建失败(比如数据库报错、参数非法),库存必须恢复,不能出现“库存扣了但订单没生成”的异常情况。
- 批量数据操作:比如批量导入100条用户数据,只要有一条数据不符合规则或插入失败,所有已经导入的数据都要回滚,保证数据库里的用户数据是完整且符合要求的。
- 跨表/跨库业务操作:一次业务操作涉及多个表(比如同时修改用户表和日志表)或多个数据库的修改,必须用事务保证所有操作的原子性。
三、代码示例(转账场景)
业务层代码
@Service public class TransferService { @Autowired private UserAccountDao userAccountDao; // 声明事务:默认发生RuntimeException时自动回滚 @Transactional public void transfer(Long fromUserId, Long toUserId, BigDecimal amount) { // 第一步:扣减转出用户的余额 userAccountDao.decreaseBalance(fromUserId, amount); // 模拟业务异常,测试事务回滚(实际开发中可能是数据库操作失败、参数校验不通过等) // if (amount.compareTo(new BigDecimal("1000")) > 0) throw new RuntimeException("单笔转账金额不能超过1000"); // 第二步:增加转入用户的余额 userAccountDao.increaseBalance(toUserId, amount); } }
DAO层代码(基于Spring Data JPA)
@Repository public interface UserAccountDao extends JpaRepository<UserAccount, Long> { @Modifying @Query("UPDATE UserAccount u SET u.balance = u.balance - :amount WHERE u.id = :userId") void decreaseBalance(@Param("userId") Long userId, @Param("amount") BigDecimal amount); @Modifying @Query("UPDATE UserAccount u SET u.balance = u.balance + :amount WHERE u.id = :userId") void increaseBalance(@Param("userId") Long userId, @Param("amount") BigDecimal amount); }
四、关键注意事项
- 回滚规则:默认只对
RuntimeException和Error触发回滚,如果需要对检查型异常(比如IOException)也回滚,要设置@Transactional(rollbackFor = Exception.class)。 - 方法权限:注解必须加在public方法上,Spring的AOP代理默认不会拦截非public方法,导致事务不生效。
- 内部调用陷阱:如果在同一个类中调用带
@Transactional的方法,AOP代理不会生效,事务不会触发。解决方法是把事务方法抽到单独的类中,或者通过ApplicationContext获取代理对象调用。
内容的提问来源于stack exchange,提问作者Shefat-Hasnain
相关产品推荐
相关产品推荐

