Spring 事务

目录

一.使用总结

二.事务回滚情况举例


一.使用总结

1.不要在接口上声明@Transactional ,而要在具体类的方法上使用 @Transactional 注解,否则注解可能无效。

2.不建议将@Transactional放置在类级的声明中,放在类级声明中会使得所有方法都有事务。故@Transactional应该放在方法级别,不需要使用事务的方法就不要放置事务,比如查询方法,否则对性能是有影响的。

3.@Transactional 注解只能应用到 public 可见度的方法上。 如果应用在protected、private或者 package可见度的方法上,也不会报错,不过事务设置不会起作用。

4.一个类中的事务方法只有在被外部类调用时,该类的事务方法才会起作用。原因:Spring在扫描bean的时候会扫描方法上是否含有@Transactional 注解,如果包含,spring会为这个bean动态的生成一个子类(即代理类:proxy)【面向切面编程】,代理类继承原来的bean。当这个有注解的方法被外部类调用时,实际上是由代理类来调用的,代理类在调用之前就会启动transaction。然而,如果这个有注解的方法是被本类中其他方法调用,那么该方法调用并没有通过代理类,而是直接通过原来的bean,所以就不会启动transaction。

5.在同一个类中,一个方法调用另一个有@Transactional注解的方法,注解是不会生效的。

6.默认情况下,Spring会对unchecked异常进行事务回滚;如果是checked异常则不回滚。只有在异常抛出的时候才会回滚,如果是catch捕获了,事务不会回滚。可以在catch里面加上throw new RuntimeException()使事务进行回滚。

7.和锁同时使用需要注意:由于Spring事务是通过AOP实现的,所以在方法执行之前会有开启事务,之后会有提交事务逻辑。而synchronized代码块执行是在事务之内执行的,可以推断在synchronized代码块执行完时,事务还未提交,其他线程进入synchronized代码块后,读取的数据不是最新的。所以必须使synchronized锁的范围大于事务控制的范围,把synchronized加到Controller层或者大于事务边界的调用层!

二.事务回滚情况举例

A类中的methodA为调用者,B类中的methodB为被调用者。methodA和methodB以propagation = Propagation.REQUIRED 为事务传播属性。

1.被调用者方法methodB内未作任何异常处理,但是在执行过程中,methodB抛出了异常。methodA会产生事务回滚。

@Service
public class TestA {

    @Autowired
    private TestB testB;
    @Transactional(propagation = Propagation.REQUIRED)
    public void methodA() {
        // dboper1 --数据库操作1
        testB.methodB();
        // dboper2 --数据库操作2
    }
}

@Service
public class TestB {
    @Transactional(propagation = Propagation.REQUIRED)
    public void methodB() {
        //dboper3 --数据库操作3
    }
}

2.被调用者方法methodB内进行了try catch处理,在执行过程中,methodB抛出了异常,但是被catch捕获。methodA不会产生事务回滚。

public class TestA {

    @Autowired
    private TestB testB;
    @Transactional(propagation = Propagation.REQUIRED)
    public void methodA() {
        // dboper1 --数据库操作1
        testB.methodB();
        // dboper2 --数据库操作2
    }
}

@Service
public class TestB {
    @Transactional(propagation = Propagation.REQUIRED)
    public void methodB() {
        try {
            //dboper3 --数据库操作3
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3.被调用者方法methodB内进行了try catch处理,但是在catch块中,显式抛出了RuntimeException。在执行过程中,methodB抛出了异常,被catch捕获后,抛给了外层调用者。methodA会产生事务回滚。原理同1。

@Service
public class TestA {

    @Autowired
    private TestB testB;
    @Transactional(propagation = Propagation.REQUIRED)
    public void methodA() {
        // dboper1 --数据库操作1
        testB.methodB();
        // dboper2 --数据库操作2
    }
}

@Service
public class TestB {
    @Transactional(propagation = Propagation.REQUIRED)
    public void methodB() {
        try {
            //dboper3 --数据库操作3
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
    }
}

4.被调用者方法methodB内未作任何异常处理。在methodA中对被调用代码块methodB进行了try catch处理。如果methodB执行过程中抛出了异常,那么会报Transaction rolled back because it has been marked as rollback-only的异常。原理:因为事务传播属性设置为Propagation.REQUIRED,那么methodB和methodA用的就是同一个事务,在执行methodB方法过程中,由于抛出了异常,那么spring就在执行methodB方法过程中将事务状态标记为rollback-only,虽然在methodA中将methodB异常捕获,但是由于事务状态已经被标记为rollback-only,所以在methodA也不会正常的提交事务,报Transaction rolled back because it has been marked as rollback-only的异常。

@Service
public class TestA {

    @Autowired
    private TestB testB;
    @Transactional(propagation = Propagation.REQUIRED)
    public void methodA() {
        // dboper1 --数据库操作1
        try {
           testB.methodB();
        } catch (Exception e) {
           
        }
        // dboper2 --数据库操作2
    }
}

@Service
public class TestB {
    @Transactional(propagation = Propagation.REQUIRED)
    public void methodB() {
        //dboper3 --数据库操作3
    }
}

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值