Spring事务总结---传播级别以及REQUIRED_NEW及NESTED的使用场景(赞)
2017-06-15 10:22
525 查看
Spring事务总结—传播级别以及REQUIRED_NEW及NESTED的使用场景(赞)
三、Spring事务的传播性与隔离级别
@Service
public class IUserServiceImpl implements IUserService {
}
我们定义了两个镜像(就是一样的Serivce)分别是UserService,UserService2,是一样的,只是相互调用,不重复上代码。
@Override
@Transactional
public void fun1() throws Exception {
}
NESTED事务使用场景
@Override
@Transactional
public void fun2() throws Exception {
//嵌套事务的使用场景
funNone();
}
//执行结果:
//userService2.funNestException()被回滚
//其他插入成功
外部的异常能触发所调用的NESTED事务回滚
@Override
@Transactional
public void fun3() throws Exception {
}
//执行结果
//全部被回滚
REQUIRES_NEW的使用场景
@Override
@Transactional
public void fun4() throws Exception {
//而REQUIRES_NEW,当被调用时,就相当于暂停(挂起)当前事务,先开一个新的事务去执行REQUIRES_NEW的方法,如果REQUIRES_NEW中的异常得到了处理
//那么他将不影响调用者的事务,同时,调用者之后出现了异常,同样也不会影响之前调用的REQUIRES_NEW方法的事务.
}
//执行结果
//funNone()正常持久化
// userService2.funRequireNewException()回滚
@Override
@Transactional
public void fun5() throws Exception {
}
//执行结果
//userService2.funRequireNew();正常持久化
//其他操作被回滚
如果调用的是REQUIRED类型,即使处理了被调用方法抛出的异常仍然会被回滚。
@Override
@Transactional
public void fun6() throws Exception {
}
//执行结果
//被回滚
总结:附上一段我觉得很好的总结(Jurgen Hoeller原话翻译)(翻译从这里拷的)
PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 “内部” 事务, 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行。
另一方面, PROPAGATION_NESTED 开始一个 “嵌套的” 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint, 如果这个嵌套事务失败, 我们将回滚到此 savepoint, 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交。
由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 潜套事务也会被 commit, 这个规则同样适用于 roll back。
四、Spring事务自我调用的坑
@Override
@Transactional
public void fun7() throws Exception {
}
例如上面Nested的特性就没了,其运行结果是三个发生insert的语句都成功插入到数据库了。
org.aspectj
aspectjweaver
${aspectj.version}
2、开启暴露AOP代理到ThreadLocal支持
3、在自我调用的时候这么写
fun8() Exception {
((IUserService) AopContext.()).funRequire();
}
这样,就能让配置在该方法上的事务发挥应有的特性啦。
原因我也来总结一句,因为开启事务和事务回滚,实际这个过程是aop代理帮忙完成的,当调用一个方法时,他会先检查时候有事务,有则开启事务,当调用本类的方法是,他并没有将其视为proxy调用,而是方法的直接调用,所以也就没有检查该方法是否含有事务这个过程,那么他生命的事务也就不成立了。
三、Spring事务的传播性与隔离级别
Spring它对JDBC的隔离级别作出了补充和扩展,其提供了7种事务传播行为。(通俗解释原址) 1、PROPAGATION_REQUIRED:默认事务类型,如果没有,就新建一个事务;如果有,就加入当前事务。适合绝大多数情况。 2、PROPAGATION_REQUIRES_NEW:如果没有,就新建一个事务;如果有,就将当前事务挂起。 3、PROPAGATION_NESTED:如果没有,就新建一个事务;如果有,就在当前事务中嵌套其他事务,当前事务设置一个保存点,savepoint。 4、PROPAGATION_SUPPORTS:如果没有,就以非事务方式执行;如果有,就使用当前事务。 5、PROPAGATION_NOT_SUPPORTED:如果没有,就以非事务方式执行;如果有,就将当前事务挂起。即无论如何不支持事务。 6、PROPAGATION_NEVER:如果没有,就以非事务方式执行;如果有,就抛出异常。 7、PROPAGATION_MANDATORY:如果没有,就抛出异常;如果有,就使用当前事务。 第4、5、6、7种特性很好理解了,主要是前三种特性比较容易混淆或用错。 那么PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED的区别在哪呢? 什么有就创建一个什么嵌套挂起,很明显不如一些使用场景清晰,那就直接上例子。 先定义一些实验性的方法。(例子代码:https://git.oschina.net/sluggarddd/spring-tx-demo.git)
@Service
public class IUserServiceImpl implements IUserService {
@Resource IUserDAO userDAO; @Resource IUserService2 userService2; //不带事务的方法 public void funNone() throws Exception { save(new UserEntity("zhw")); } //启动默认事务的方法 @Transactional(propagation = Propagation.REQUIRED) public void funRequire() throws Exception { save(new UserEntity("wlj")); } //启动默认事务的方法 @Transactional(propagation = Propagation.REQUIRED) public void funRequire2() throws Exception { save(new UserEntity("shifang")); } //启动默认事务的方法,抛出RuntimeException @Override @Transactional(propagation = Propagation.REQUIRED) public void funRequireException() throws Exception { save(new UserEntity("max")); throwExcp(); } //启动嵌套事务的方法 @Transactional(propagation = Propagation.NESTED) public void funNest() throws Exception { save(new UserEntity("yunxinghe")); } //启动嵌套事务的方法,但会抛出异常 @Override @Transactional(propagation = Propagation.NESTED) public void funNestException() throws Exception { save(new UserEntity("edward")); throwExcp(); } //REQUIRES_NEW事务的方法 @Transactional(propagation = Propagation.REQUIRES_NEW) public void funRequireNew() throws Exception { save(new UserEntity("kb")); } //REQUIRES_NEW事务的方法,但会抛出异常 @Override @Transactional(propagation = Propagation.REQUIRES_NEW) public void funR 4000 equireNewException() throws Exception { save(new UserEntity("laura")); throwExcp(); } //抛出异常 private void throwExcp() throws Exception { throw new RuntimeException("boom"); } //保存数据 public int save(UserEntity userEntity) throws Exception { userDAO.save(userEntity); return userEntity.getId(); }
}
我们定义了两个镜像(就是一样的Serivce)分别是UserService,UserService2,是一样的,只是相互调用,不重复上代码。
@Override
@Transactional
public void fun1() throws Exception {
//数据库操作 funNone(); //调用另一个service的方法 userService2.funNest(); //当调用另一个Service的method的时候,想要将他的事务加到现在这个事务中,很可能自然而然想到了嵌套 //这么想就错了,Required的定义里已经说明了如果没有,就新建一个事务;如果有,就加入当前事务。 //那么直接使用Required就满足需求 //这样在方法中任何地方发生unchecked异常将触发整个方法的回滚 //而Nested的使用场景下面再介绍
}
NESTED事务使用场景
@Override
@Transactional
public void fun2() throws Exception {
//嵌套事务的使用场景
funNone();
try { //当所调用的方法为NESTED事务,该事务的回滚可以不影响到调用者的事务 //当然如果没有catch exception,异常冒泡而出,就将触发调用者事务的回滚 userService2.funNestException(); } catch (Exception e) { //do something } userService2.funRequire();
}
//执行结果:
//userService2.funNestException()被回滚
//其他插入成功
外部的异常能触发所调用的NESTED事务回滚
@Override
@Transactional
public void fun3() throws Exception {
//嵌套事务的使用场景 funNone(); try { //调用的事务为NESTED事务的方法 userService2.funNest(); } catch (Exception e) { //do something } userService2.funRequire(); //此时在调用者处,触发一个unchecked异常 throwExcp(); //此时会发现包括调用的userService2.funNest()也被回滚了 //也就是说,当调用的方法是NESTED事务,该方法抛出异常如果得到了处理(try-catch),那么该方法发生异常不会触发整个方法的回滚 //而调用者出现unchecked异常,却能触发所调用的nested事务的回滚.
}
//执行结果
//全部被回滚
REQUIRES_NEW的使用场景
@Override
@Transactional
public void fun4() throws Exception {
//而REQUIRES_NEW,当被调用时,就相当于暂停(挂起)当前事务,先开一个新的事务去执行REQUIRES_NEW的方法,如果REQUIRES_NEW中的异常得到了处理
//那么他将不影响调用者的事务,同时,调用者之后出现了异常,同样也不会影响之前调用的REQUIRES_NEW方法的事务.
//不会回滚 funNone(); try { //当异常得到处理,外部不会触发回滚 userService2.funRequireNewException(); } catch (Exception e) { }
}
//执行结果
//funNone()正常持久化
// userService2.funRequireNewException()回滚
@Override
@Transactional
public void fun5() throws Exception {
//数据库操作 funNone(); //调用RequireNew类型事务的方法,调用者的异常回滚不会影响到它 userService2.funRequireNew(); //数据库操作 funNone(); //抛出unchecked异常,触发回滚 throwExcp();
}
//执行结果
//userService2.funRequireNew();正常持久化
//其他操作被回滚
如果调用的是REQUIRED类型,即使处理了被调用方法抛出的异常仍然会被回滚。
@Override
@Transactional
public void fun6() throws Exception {
funNone(); try { //当调用的是Required时,就算异常被处理了,整个方法也将会回滚 userService2.funRequireException(); } catch (Exception e) { System.out.println(e.getMessage()); }
}
//执行结果
//被回滚
总结:附上一段我觉得很好的总结(Jurgen Hoeller原话翻译)(翻译从这里拷的)
PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 “内部” 事务, 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行。
另一方面, PROPAGATION_NESTED 开始一个 “嵌套的” 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint, 如果这个嵌套事务失败, 我们将回滚到此 savepoint, 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交。
由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 潜套事务也会被 commit, 这个规则同样适用于 roll back。
四、Spring事务自我调用的坑
当Spring的事务在同一个类时,它的自我调用时事务就完犊子了!(不知道这个的时候被坑出翔) 当同一个类的方法之间事务发生自我调用,其事务的特性将失效。
@Override
@Transactional
public void fun7() throws Exception {
funRequire(); try { //本应回滚这个方法,但发生了异常并没有回滚 funNestException(); } catch (Exception e) { System.out.println(e.getMessage()); } funRequire();
}
例如上面Nested的特性就没了,其运行结果是三个发生insert的语句都成功插入到数据库了。
原因我自己肯定没别人总结的好(连问题都说的不太清楚),就直接放链接了(原因点此),不想看的直接上解决方法。 1、首先引入
org.aspectj
aspectjweaver
${aspectj.version}
2、开启暴露AOP代理到ThreadLocal支持
3、在自我调用的时候这么写
fun8() Exception {
((IUserService) AopContext.()).funRequire();
{ ((IUserService) AopContext.()).funNestException(); } (Exception e) { System..println(e.getMessage()); } ((IUserService) AopContext.()).funRequire();
}
这样,就能让配置在该方法上的事务发挥应有的特性啦。
原因我也来总结一句,因为开启事务和事务回滚,实际这个过程是aop代理帮忙完成的,当调用一个方法时,他会先检查时候有事务,有则开启事务,当调用本类的方法是,他并没有将其视为proxy调用,而是方法的直接调用,所以也就没有检查该方法是否含有事务这个过程,那么他生命的事务也就不成立了。
相关文章推荐
- Spring事务总结---传播级别以及REQUIRED_NEW及NESTED的使用场景(赞)
- Spring事务总结---传播级别以及REQUIRED_NEW及NESTED的使用场景
- REQUIRED、REQUIRES_NEW、NESTED 3个 spring 事务传播级别使用场景
- spring事务 Propagation.REQUIRES_NEW、Propagation.NESTED、Propagation.REQUIRED使用时候发现的
- Spring 事务传播属性以及PROPAGATION_NESTED 和PROPAGATION_REQUIRES_NEW
- [spring]事务传播级别隔离级别以及高并发下的应用经验
- 数据库隔离级别以及Spring事务传播
- [spring]事务传播级别隔离级别以及高并发下的应用经验
- Spring事务管理与传播机制详解以及使用实例
- [spring]事务传播级别隔离级别以及高并发下的应用经验
- spring事务传播级别隔离级别以及高并发下的应用经验
- [spring]事务传播级别隔离级别以及高并发下的应用经验
- Spring事务传播特性实例解析(以及如何使用注解形式事务)
- [spring]事务传播级别隔离级别以及高并发下的应用经验
- spring的事务传播级别及场景
- spring整合hibernate事务管理的四种方式,以及事务的传播行为和隔离级别介绍
- Spring的事务ACID特性、隔离级别以及传播行为
- Spring中声明式事务的注解@Transactional的参数的总结(REQUIRED和REQUIRES_NEW的与主方法的回滚问题)
- Spring_使用spring的注解式事务管理_事务的传播行为和隔离级别
- [spring]事务传播级别隔离级别以及高并发下的应用经验