Spring的事务
@Transactional
生效原则1:除非特殊配置(比如使用AspectJ静态织入实现AOP),否则只有定义在public方法上的@Transactional才能生效。
原因:Spring默认通过动态代理的方式实现AOP,对目标方法进行增强,private方法无法代理到,Spring自然也无法动态增强事务处理逻辑。
生效原则2:必须通过代理过的类从外部调用目标方法才能生效
回滚
事务即使生效不一定能回滚:通过AOP实现事务处理,使用try...catch...来包裹标记了@Transactional注解的方法,当方法出现了异常并且满足一定条件的时候,在catch里面我们可以设置事务回滚,没有异常则直接提交事务。
一定条件
第一,只有异常传播出了标记了@Transactional注解的方法,事务才能回滚。 //在Spring的TransactionAspectSupport类中 invokeWithinTransaction方法 try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // target invocation exception completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); }
第二,默认情况下,出现RuntimeException(非受检异常)或Error的时候,Spring才会回滚事务。即受检异常(一般是业务异常,或者说类似另一种方法的返回值,出现这样的异常可能业务还能完成,所以不会主动回滚);而Error或RuntimeException代表了非预期的结果,应该回滚 /** * The default behavior is as with EJB: rollback on unchecked exception * ({@link RuntimeException}), assuming an unexpected outcome outside of any * business rules. Additionally, we also attempt to rollback on {@link Error} which * is clearly an unexpected outcome as well. By contrast, a checked exception is * considered a business exception and therefore a regular expected outcome of the * transactional business method, i.e. a kind of alternative return value which * still allows for regular completion of resource operations. * <p>This is largely consistent with TransactionTemplate's default behavior, * except that TransactionTemplate also rolls back on undeclared checked exceptions * (a corner case). For declarative transactions, we expect checked exceptions to be * intentionally declared as business exceptions, leading to a commit by default. * @see org.springframework.transaction.support.TransactionTemplate#execute */ @Override public boolean rollbackOn(Throwable ex) { return (ex instanceof RuntimeException || ex instanceof Error); }
手动修复
1. 手动设置让当前事务处于回滚状态 @Transactional public void createUser(User user) { try { userDao.save(new User(user)); throw new RuntimeException("error"); } catch (Exception ex) { log.error("create user failed", ex); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } } 2. 在注释中声明,期望遇到所有的Exception都回滚事务(覆盖默认不回滚受检异常) @Transactional(rollbackFor = Exception.class) public void createUser(User user) { throws IOException { userDao.save(new User(user)); otherTask(); }
独立事务
如果方法涉及多个数据库操作,并希望将他们作为独立的事务进行提交或回滚,我们考虑进一步细化配置事务传播方式,也就是@Transactional 注解的 Propagation 属性。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通