注解@Transactional

注意常用的该注解有两个,一个是java本身的,一个是spring的
org.springframework.transaction.annotation.Transactional
javax.transaction.Transactional
这两个在使用上基本没什么区别,只是属性名称稍有不同
其中,rollback的默认类为RuntimeException和Error,隔离级别默认为数据源的隔离级别,传播行为默认为REQUIRE
下面以spring的注解使用为例

在service的实现类的方法上使用

demo1

1
2
3
4
public User createUser(User user) {
userRepository.save(user);
throw new RuntimeException();
}

demo2

1
2
3
4
5
@Transactional(rollbackOn = Exception.class)
public User createUser(User user) {
userRepository.save(user);
throw new RuntimeException();
}

demo3

1
2
3
4
5
@Transactional
public User createUser(User user) {
userRepository.save(user);
throw new RuntimeException();
}

demo4

1
2
3
4
5
@Transactional
public User createUser(User user) throws Exception {
userRepository.save(user);
throw new Excepton();
}
ps:这里要注意的是Exception异常的分类,运行时异常(RuntimeException/未检查异常)
和非运行时异常(非RuntimeException/已检查异常),所有的RuntimeException可以不
需要捕获异常,默认的在throws里面已经处理,而非RuntimeException都需要,通过try
catch 或者 throws 来手动处理捕获

demo5

@Transactional(rollbackOn = Exception.class)
public User createUser(User user) throws Exception {
    userRepository.save(user);
    throw new Exception();
}

运行结果

数据不会因为异常而插入数据库的demo有:demo1和demo4,其他所有的的都会因为异常而发生事务的回滚操作

其中,

demo1:因为没有使用事务,所有在save方法完成之后直接commit事务,正常提交
demo2:回滚的异常设置为Exception,而RuntimeException是Exception的子类,所有发生异常事务回滚
demo3:采用默认的设置,@Transactional默认的设置为RuntimeException和Error,这两者及其子类,那么在发生RuntimeException异常时,事务发生回滚
demo4:采用默认的设置,但是抛出的异常时Exception,无法被事务捕获,所以无法让事务回滚
demo5:手动设置回滚的异常为Exception,那么发生所有的Exception或者子异常,都会触发回滚操作

事务无法生效的解决思路

  • 首先要确认数据库和表的存储引擎是否是InnoDB,如果是MyISAM是不支持事务的
  • 如果事务加在Service接口的方法上,那么要确定,实现类是否是通过java动态代理进行实例化的,如果不是通过代理,那么事务也不会执行,因为cglib是不用实现接口的
  • 事务的异常处理是否合理,具体的思路参考上面
  • 还有一点需要注意,在spring中定义的事务的方法是否是public类型