参考: https://blog.csdn.net/u013517797/article/details/82926410
https://blog.csdn.net/lsziri/article/details/80656600
https://blog.csdn.net/tianyaleixiaowu/article/details/73123242

概念

事务: 如果一个包含多个步骤的业务操作被事务管理, 那么这些操作要么同时成功, 要么同时失败.

事务的四大特性

  • 原子性: 是不可分隔的最小操作单位, 要么同时成功, 要么同时失败
  • 持久性: 当事务提交或回滚后, 数据库会持久化的保存数据
  • 隔离性: 多个事务之间会相互独立
  • 一致性: 事务操作前后, 数据总量不变

事务的隔离级别

问题:

  • 脏读: 一个事务读取到另一个事务没有提交的数据
  • 不可重复读(虚读): 在同一个事务中, 两次读取到的数据不一样
  • 幻读: 一个事务操作数据表中所有记录, 另一个事务添加了一条数据, 则第一个事务查询不到自己的修改

隔离级别:
1. read uncommitted:读未提交, 表示一个事务可以读取到另一个事务还未提交的数据
产生的问题:脏读、不可重复读、幻读
2. read committed:读已提交 (Oracle), 表示一个事务只能读取到另一个事务已经提交的数据
产生的问题:不可重复读、幻读
3. repeatable read:可重复读 (MySQL默认), 表示一个事务在整个过程中可以重复执行某个查询, 并且每次返回的记录都相同, 即使在多次查询之间有新增的数据满足该查询, 这些新增的记录也会被忽略
产生的问题:幻读
4. serializable:串行化, 所有的事务依次逐个执行.
可以解决所有的问题

  • 注意:隔离级别从小到大安全性越来越高,但是效率越来越低
    数据库查询隔离级别:
    select @@tx_isolation;
    数据库设置隔离级别:
    set global transaction isolation level 级别字符串;

事务的传播行为

  • REQUIRED :如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  • SUPPORTS :如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • MANDATORY :如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  • REQUIRES_NEW :创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • NOT_SUPPORTED :以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • NEVER :以非事务方式运行,如果当前存在事务,则抛出异常。
  • NESTED :如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 REQUIRED 。

image.png


声明式事务

使用

在启动类开启@EnableTransactionManagement, 然后在类或方法上注解@Transactional即可
可以通过propagation以及isolation指定传播范围以及隔离级别
示例:

  1. @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)

注解失效场景

  • @Transactional 注解只能应用到 public 可见度的方法上, 其余失效
  • 默认情况下,Spring会对unchecked异常进行事务回滚;如果是checked异常则不回滚

补充:
unchecked Exception(非受检异常==运行期异常): NPE, ClassCastException, OutOfIndexException…
checked Exception(受检异常==编译器异常): IOException, TimeoutException, SQLException, ClassNotFoundException…

  • 如果在同一个类中,一个非@Transaction的方法调用有@Transaction的方法不会生效,因为不走代理
  • 不同服务,非@Transaction的方法调@Transaction的方法,里层有事务,但外层没有事务,也需注意

例:
1.throw new Exception—>不生效, 因为只回滚RuntimeException下面的异常, 其余类型需要手动配置@Transactional(rollbackFor = Exception.class)
2.Mysql—mylsam引擎不支持事务
3.注解修饰的方法try—catch后事务不生效, 无异常抛出


编程式事务

使用

transactionTemplate使用

  1. @Autowired
  2. private TransactionTemplate transactionTemplate;
  3. @Override
  4. public Integer insert() {
  5. Integer i = transactionTemplate.execute(new TransactionCallback<Integer>() {
  6. @Override
  7. public Integer doInTransaction(TransactionStatus transactionStatus) {
  8. try {
  9. Integer i = userMapper.insert();
  10. // 除0错误演示
  11. System.out.println(1 / 0);
  12. return i;
  13. } catch (Exception e) {
  14. transactionStatus.setRollbackOnly();
  15. return 0;
  16. }
  17. }
  18. });
  19. return i;
  20. }
  21. ------------------上面例子用Lambda表达式优化下
  22. @Override
  23. public Integer insert() {
  24. return transactionTemplate.execute(t -> {
  25. try {
  26. return userMapper.insert();
  27. } catch (Exception e) {
  28. t.setRollbackOnly();
  29. }
  30. return 0;
  31. });
  32. }
  33. ------------------
  34. @Override
  35. public Integer insert() {
  36. transactionTemplate.execute(new TransactionCallbackWithoutResult() {
  37. @Override
  38. protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
  39. try {
  40. userMapper.insert();
  41. // 除0错误用以演示
  42. System.out.println(1 / 0);
  43. } catch (Exception e) {
  44. transactionStatus.setRollbackOnly();
  45. }
  46. }
  47. });
  48. return null;
  49. }

PlatformTransactionManager使用

  1. @Autowired
  2. private PlatformTransactionManager transactionManager;
  3. @Override
  4. public Integer insert() {
  5. DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
  6. definition.setPropagationBehavior(Propagation.REQUIRED.value());
  7. definition.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
  8. definition.setTimeout(-1);
  9. TransactionStatus status = transactionManager.getTransaction(definition);
  10. try {
  11. Integer i = userMapper.insert();
  12. // 除0错误演示
  13. System.out.println(1 / 0);
  14. this.transactionManager.commit(status);
  15. return i;
  16. } catch (Exception var8) {
  17. this.transactionManager.rollback(status);
  18. throw var8;
  19. }
  20. }

参考学习

巨益事务类

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by Fernflower decompiler)
  4. //
  5. package com.greatonce.core.database;
  6. import org.springframework.transaction.PlatformTransactionManager;
  7. import org.springframework.transaction.TransactionStatus;
  8. import org.springframework.transaction.annotation.Isolation;
  9. import org.springframework.transaction.annotation.Propagation;
  10. import org.springframework.transaction.support.DefaultTransactionDefinition;
  11. public class ManualTransactionTemplate {
  12. private PlatformTransactionManager transactionManager;
  13. public ManualTransactionTemplate(PlatformTransactionManager transactionManager) {
  14. this.transactionManager = transactionManager;
  15. }
  16. public void execute(ManualTransactionTemplate.TransactionRunnable runnable) {
  17. this.execute(Propagation.REQUIRED, Isolation.DEFAULT, -1, runnable);
  18. }
  19. public void execute(Propagation propagation, ManualTransactionTemplate.TransactionRunnable runnable) {
  20. this.execute(propagation, Isolation.DEFAULT, -1, runnable);
  21. }
  22. public void execute(Propagation propagation, Isolation isolation, int timeout, ManualTransactionTemplate.TransactionRunnable runnable) {
  23. DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
  24. definition.setPropagationBehavior(propagation.value());
  25. definition.setIsolationLevel(isolation.value());
  26. definition.setTimeout(timeout);
  27. TransactionStatus status = this.transactionManager.getTransaction(definition);
  28. try {
  29. runnable.run();
  30. this.transactionManager.commit(status);
  31. } catch (Exception var8) {
  32. this.transactionManager.rollback(status);
  33. throw var8;
  34. }
  35. }
  36. public <T> T executeWithResult(ManualTransactionTemplate.TransactionCallable<T> callable) {
  37. return this.executeWithResult(Propagation.REQUIRED, Isolation.DEFAULT, -1, callable);
  38. }
  39. public <T> T executeWithResult(Propagation propagation, ManualTransactionTemplate.TransactionCallable<T> callable) {
  40. return this.executeWithResult(propagation, Isolation.DEFAULT, -1, callable);
  41. }
  42. public <T> T executeWithResult(Propagation propagation, Isolation isolation, int timeout, ManualTransactionTemplate.TransactionCallable<T> callable) {
  43. DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
  44. definition.setPropagationBehavior(propagation.value());
  45. definition.setIsolationLevel(isolation.value());
  46. definition.setTimeout(timeout);
  47. TransactionStatus status = this.transactionManager.getTransaction(definition);
  48. try {
  49. T t = callable.call();
  50. this.transactionManager.commit(status);
  51. return t;
  52. } catch (Exception var8) {
  53. this.transactionManager.rollback(status);
  54. throw var8;
  55. }
  56. }
  57. @FunctionalInterface
  58. public interface TransactionCallable<V> {
  59. V call();
  60. }
  61. @FunctionalInterface
  62. public interface TransactionRunnable {
  63. void run();
  64. }
  65. }

使用

  1. getTransactionTemplate().execute(() -> {
  2. b2bStockOutOrderDetailService.batchModify(outOrderDetails);
  3. stockOccupancyService.batchCreate(occupancies);
  4. updateOrder.setAuditedTime(LocalDateTime.now());
  5. update(updateOrder);
  6. });
  7. ---------------
  8. int count = getTransactionTemplate().executeWithResult(() -> insertBatch(collection));

事务实测

同一个类中两个方法的调用

情况一: 实测安全!

  1. @Transactional
  2. public void method1() {
  3. method2();
  4. }
  5. @Transactional
  6. public void method2() {
  7. }

情况二: 实测安全!

  1. @Transactional
  2. public void method1() {
  3. method2();
  4. }
  5. private void method2() {
  6. }

情况三: 实测安全!

  1. @Transactional
  2. public void method1() {
  3. method2();
  4. }
  5. public void method2() {
  6. }

情况四: 不安全!

  1. public void method1() {
  2. method2();
  3. }
  4. @Transactional
  5. public void method2() {
  6. }