@Transactional注解配置事务管理

Spring事务管理分为编程式和声明式:

  • 编程式:通过编码实现事务。
  • 声明式:基于AOP,将具体业务逻辑与事务处理解耦,使业务代码不受污染。
    声明式有两种方式:一种是在配置文件xml中做相关的事务规则声明。另一种是基于@Transactional注解。

前提明确:

  1. 默认配置下Spring只会回滚运行时,未检查异常(继承RuntimeException异常)或者Error。
  2. @Transactional注解只能应用到public 方法才有效。

@Transactional注解的属性介绍:

1、value和transactionManager属性:
当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器。

2、propagation属性:
事务的传播行为,默认为Propagation.REQUIRED。
可选的值有:

  • Propagation.REQUIRED

如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。

  • Propagation.SUPPORTS

如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。

  • Propagation.MANDATORY

如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。

  • Propagation.REQUIRES_NEW

重新创建一个新的事务,如果当前存在事务,暂停当前的事务。

  • Propagation.NOT_SUPPORTED

以非事务的方式运行,如果当前存在事务,暂停当前的事务。

  • Propagation.NEVER

以非事务的方式运行,如果当前存在事务,则抛出异常。

  • Propagation.NESTED

和 Propagation.REQUIRED 效果一样。

3、isolation 属性:

事务的隔离级别,默认值为 Isolation.DEFAULT,底层数库默认的隔离级别。

  • Isolation.READ_UNCOMMITTED:读未提交。
  • Isolation.READ_COMMITTED:读已提交。
  • Isolation.REPEATABLE_READ:可重复读。
  • Isolation.SERIALIZABLE:串行化读。

4、timeout 属性:

事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。

5、readOnly 属性:

指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。

6、rollbackFor 属性:

用于指定能够触发事务回滚的异常类型,可以指定多个异常类型。

7、noRollbackFor 属性:

抛出指定的异常类型,不回滚事务,也可以指定多个异常类型。

@Transactional 事务实现机制:

在应用系统调用声明了 @Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据 @Transactional 的属性配置信息,这个代理对象决定该声明 @Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑, 最后根据执行情况是否出现异常,利用抽象事务管理器 AbstractPlatformTransactionManager 操作数据源 DataSource 提交或回滚事务。

Spring AOP 代理有 CglibAopProxy 和 JdkDynamicAopProxy 两种。
对于 CglibAopProxy,需要调用其内部类的 DynamicAdvisedInterceptor 的 intercept 方法。
对于 JdkDynamicAopProxy,需要调用其 invoke 方法。

事务管理的框架是由抽象事务管理器 AbstractPlatformTransactionManager 来提供的,而具体的底层事务处理实现,由 PlatformTransactionManager 的具体实现类来实现,如事务管理器 DataSourceTransactionManager。不同的事务管理器管理不同的数据资源 DataSource,比如 DataSourceTransactionManager 管理 JDBC 的 Connection。

propagation 属性特别测试:

@Transactional(propagation = Propagation.REQUIRED)
@Override
public void save() {

    method1();

    User user = new User("222");
    userMapper.insertSelective(user);

    if (true) {
        throw new RuntimeException("save 抛异常了");
    }
}

public void method1() {
    User user = new User("宫本武藏");
    userMapper.insertSelective(user);
}

在save方法中调用了method1方法,然后抛出异常,两个数据都会回滚,即使method1方法没有事务注解。

@Transactional(propagation = Propagation.REQUIRED)
@Override
public void save() {

    method1();

    User user = new User("服部半藏");
    userMapper.insertSelective(user);

    if (true) {
        throw new RuntimeException("save 抛异常了");
    }
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void method1() {
    User user = new User("宫本武藏");
    userMapper.insertSelective(user);
}

如果method1方法自己也使用事务注解,新开一个事务,但结果还是令人意外。两个方法还是属于同一个事务,save方法抛出异常,还是会导致两条数据回滚,不会插到数据库。
原因: 在默认的代理模式下,只有目标方法由外部类调用时,才能被Spring的事务拦截器拦截。如果时同一个类的两个方法直接调用,是不会被Spring的事务拦截器拦截的。当然可以不使用默认的代理,比如使用AspectJ取代AOP。

@Service
public class OtherServiceImpl implements OtherService {

    @Autowired
    private UserMapper userMapper;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void method1() {
        User user = new User("风魔小太郎");
        userMapper.insertSelective(user);
    }
}

不同类的方法之间调用,save方法抛出异常,不会影响method1方法的数据插入数据库。
两个方法的事务是不同的,save方法的事务只会回滚save方法的数据插入。

@Autowired
private OtherService otherService;

@Transactional(propagation = Propagation.REQUIRED)
@Override
public void save() {

    otherService.method1();

    User user = new User("服部半藏");
    userMapper.insertSelective(user);

    if (true) {
        throw new RuntimeException("save 抛异常了");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值