spring-transactional初步了解

spring-transactional

案例简介

本案例主要用于深入了解 Spring 的事务注解@Transactional

@Transactional 特性

  1. @Transactional注解只能应用到 public 修饰符上,对其他修饰符不起作用,但不报错。
  2. @Transactional 一般加到实现类或实现类方法上,不要加到接口或接口方法上。
  3. @Transactional仅仅对 unchecked 异常进行事务异常回滚;如果是 checked 异常则不进行异常回滚。
    • unchecked 异常一般为错误或运行时异常
      • Error:Throwable 的子类。著名的 VirtualMachineError 是 Error 的子类之一,VirtualMachineError 还有 StackOverflowError、OutOfMemoryError 等子类。
      • RuntimeException:Exception 的子类,而 Exception 同样是 Throwable 的子类。RuntimeException 下面包括 NPE,ClassCastException,ArithmaticException 等异常,这些错误的特点是不用被显式地抛出或捕获,开发者通过仔细检查代码可以避免这些异常。
    • checked 异常则为编译过程中的异常
      • 其他 Exception:除了 RuntimeException 之外其他的 Exception 的子类,包括 FileNotFoundException,IOException,SQLException 等,这些异常的特点是必须被代码抛出或捕获,否则编译都无法通过。

@Transactional 有效场景

  1. 正常执行写操作

    @Override
    @Transactional
    public int updateById(Employee employee, Integer empId) {
        return employeeMapper.updateById(employee, empId);
    }
    
  2. unchecked 异常

    • RuntimeException

      @Override
      @Transactional
      public int updateByIdRuntimeException(Employee employee, Integer empId) {
          int effect = employeeMapper.updateById(employee, empId);
          System.out.println(1 / 0);
          return effect;
      

}
```

 调用此方法,在执行此方法的语句`System.out.println(1 / 0);`时会抛出运行时异常中的算术异常(ArithmaticException),事务会回滚,数据库中的数据不会被改变。
  • OutOfMemoryError

    写一个类来制造堆内存溢出

    public class HeapOOM {
    
        static class OOMObject {
        }
    
        public static void mockHeapOOM() {
            List<Object> objects = new ArrayList<>();
    
            while (true) {
                objects.add(new OOMObject());
            }
        }
    }
    

    可以调用此类的静态方法 mockHeapOOM 不停地创建 OOMObject 对象并将其添加至数组中,而被数组强引用的对象无法被 GC 回收,堆内存很快被消耗完毕。

    @Override
    @Transactional
    public int updateByIdOOM(Employee employee, Integer empId) {
        int effect = employeeMapper.updateById(employee, empId);
        HeapOOM.mockHeapOOM();
        return effect;
    }
    

    打开 IntelliJ IDEA 的 Edit Configuration,在 VM Options 一栏为调用 updateByIdOOM 方法的单元测试配置好 JVM 参数。

    -ea -Xmx10m -Xms5m  -XX:+HeapDumpOnOutOfMemoryError
    
    • -ea 可以打开断言机制
    • -Xmx10m -Xms5m 表示堆最大可用值是 10M,堆初始值为 5M
    • -XX:+HeapDumpOnOutOfMemoryError 打印堆溢出报错信息

    运行单元测试方法,控制台中报如下错误信息:

    java.lang.OutOfMemoryError: GC overhead limit exceeded
    

    查看数据库,数据没有被改变,所以此时事务正常回滚。

@Transactional 无效场景

  1. checked 异常

    @Override
    @Transactional
    public void updateByIdException(Employee employee, Integer empId) throws IOException {
        employeeMapper.updateById(employee, empId);
        throw new IOException("模拟 IO 错误");
    }
    

    调用此方法,会在throw new IOException("模拟 IO 错误")时抛出模拟的错误,但是事务并不回滚,数据库中的数据发生了改变。这是因为 IOException 属于 checked 异常,@Transactional 默认情况下不对 checked 异常进行事务回滚。此时,想要在抛出 checked 异常时进行事务回滚,需要在 @Transactional后面配置上rollBackFor属性:

    @Override
    @Transactional(rollbackFor = IOException.class)
    public void updateByIdException(Employee employee, Integer empId) throws IOException {
        employeeMapper.updateById(employee, empId);
        throw new IOException("模拟 IO 错误");
    }
    

    这里配置为rollbackFor = Exception.class可以。

  2. 被没有事务控制的方法调用

    如果带有 @Transactional的方法 A 被另一个不带有@Transactional的方法 B 调用,那么调用 B 时 A 的@Transactional也会失效。

    @Override
    @Transactional
    public int updateByIdRuntimeException(Employee employee, Integer empId) {
        int effect = employeeMapper.updateById(employee, empId);
        System.out.println(1 / 0);
        return effect;
    }
    
    @Override
    public int updateByIdWithoutTransactional(Employee employee, Integer empId) {
        return updateByIdRuntimeException(employee, empId);
    }
    
    

    此时,调用 updateByIdWithoutTransactional,数据库的数据会被改变,这是由于事务不会因为在updateByIdRuntimeException中抛出 ArithmaticException而回滚。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值