File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -332,7 +332,9 @@ public @interface Transactional {
332332
333333### 事务失效问题
334334
335- 事务失效问题指的是在同一个类中的其他没有被 @Transactional 注解的方法内部调用 @Transactional 注解的方法,则 @Transactional 注解的方法的事务会失效。
335+ #### 1. 同一个类中方法调用
336+
337+ 在同一个类中的其他没有被 @Transactional 注解的方法内部调用 @Transactional 注解的方法,则 @Transactional 注解的方法的事务会失效。
336338
337339这是因为Spring AOP 代理造成的,因为只有当 @Transactional`注解的方法在类以外被调用的时候,Spring 事务管理才生效。
338340
@@ -351,14 +353,52 @@ public class StudentService {
351353 public void insertB () {
352354 // ...
353355 }
354- }
356+ }Copy to clipboardErrorCopied
355357```
356358
357359可以采用以下 2 种方式解决事务失效问题:
358360
359361- 避免同一类中自调用
360362- 使用 AspectJ 取代 Spring AOP 代理
361363
364+ #### 2. try-catch 导致事务失效
365+
366+ ``` java
367+ StudentServiceImplA implements StudentService {
368+ @Autowired
369+ studentDao;
370+
371+ @Autowired
372+ studentService;
373+
374+ @Transactional
375+ insertA(){
376+ try {
377+ // 对数据库操作,插入 A 数据
378+ studentService. insertB(); // 插入 B 数据
379+ } catch (Exception e) {
380+ e. printStackTrace();
381+ }
382+ }
383+ }
384+ ```
385+
386+ 如果 insertB() 内部抛了异常,被 insertA() 方法 catch 了该异常,则该事务不能正常回滚。
387+
388+ 这是因为当 ServiceB 中抛出异常后,ServiceB 标识当前事务需要 rollback 。但是ServiceA 中由于捕获这个异常并进行处理,ServiceA 认为当前事务应该正常commit ,会抛出UnexpectedRollbackException 异常。
389+
390+ Spring 的事务是在调用业务方法之前开始的,业务方法执行完毕之后才执行 commit 或者 rollback,事务是否执行取决于是否抛出运行时异常。如果抛出运行时异常并在业务方法中没有 catch 到的话,事务会回滚。
391+
392+ 解决该事务失效问题:
393+
394+ 在业务方法中一般不需要 catch 异常,如果非要 catch 则一定要抛出运行时异常,或者注解中指定抛异常类 @Transactional (rollbackFor=Exception.class)。
395+
396+ #### 3. 数据库引擎不支持事务
397+
398+ 事务能否生效数据库引擎是否支持事务是关键。
399+
400+ 常用的 MySQL 数据库默认使用支持事务的InnoDB 存储引擎。如果数据库引擎切换成不支持事务的 MyIsam,那么事务就从根本上失效了。
401+
362402### 使用注意事项
363403
364404- 正确的设置 @Transactional 的 rollbackFor 和 propagation 属性,否则事务可能会回滚失败
You can’t perform that action at this time.
0 commit comments