简单了解spring中@Transactional注解支持的七种事务的传播行为
简单说一下@Transactional注解的作用吧,看下面的代码
public void deletaAndAddUser() {
// 根据id删除用户
deleteUserById(15);
// 这里会出现算数异常
int i = 9 / 0;
// 添加用户
UserInfo user = new UserInfo();
user.setUserName("派大星");
addUser(user);
}
如果没有添加@Transactional注解,在这个方法执行到int i = 9 / 0;
语句时,就会出现异常。导致 UserInfo user = new UserInfo(); user.setUserName("派大星"); addUser(user);
语句不会被执行,但是deleteUserById(15);
却被正常执行了。可是我们的方法是要删除的同时,还要去新增一个用户,这就出现了问题。
在方法上添加@Transactional注解就可以让两个数据库操作方法在一个事务中,也就是删除和新增必须一起执行,如果出现了异常,会回滚事务,也就是不会进行删除和新增(但是如果新增操作执行后回滚事务,MySQL数据库中表中是会自增ID的,假如表中有两条数据,它们的id分别为1 ,2。但是你下一次新增成功的数据,它的自增ID就不是3了,而是4)。
@Transactional
public void deletaAndAddUser() {
// 根据id删除用户
deleteUserById(15);
// 这里会出现算数异常
int i = 9 / 0;
// 添加用户
UserInfo user = new UserInfo();
user.setUserName("派大星");
addUser(user);
}
@Transactional注解也是可以加在类上的,代表这个类中所有的方法都要应用事务管理的规则。
好的,在简单了解了@Transactional注解的作用后,我们再看一下事务的七种传播行为,也就是@Transactional(propagation =Propagation.REQUIRED )
后面跟着的(propagation =Propagation.REQUIRED )
这个小玩意
- 事务的七种传播行为
- REQUIRED(默认):业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到该事务中,否则为自己创建一个新的事务。
- SUPPORTS:如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分。如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行。
- NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会给它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行。
- MANDATORY:指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果业务方法在没有事务的环境下调用,容器会抛出异常。
- REQUIRES_NEW:表明不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务会被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先的事务才会恢复执行。
- NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有事务,则表现和REQUIRED。使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效
- NEVER:业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,容器会抛出异常,只有在业务方法没有关联到任何事务,才能正常执行。
顺便提一嘴,事务失效的场景吧,只提几个比较常见的场景
- 事务失效的几种常见的场景
- 异常捕获处理:也就是在@Transactional注解下的方法,使用了try catch 捕获了异常。事务通知只有拿到抛出的异常,才能进行后续的回滚处理。如果自己try catch 捕获了异常,事务无法正常回滚。
- 非public方法导致的事务失效:Spring中的事务代理,要求方法一定是public的
- 方法自身使用this调用另一个方法:this会导致引用逃逸,spring的事务代理是基于动态代理的