Spring oralce 中的事务传播属性 传播级别 PROPAGATION 详解介绍实例--更多实例更新中

4 篇文章 0 订阅
4 篇文章 0 订阅

 

Spring中的事务传播属性详解

 ---Spring oralce 中的事务传播属性 传播级别 PROPAGATION 详解介绍实例

 ---更多实例更新中.......

【一】事务传播的级别:按照对事务要求的程度,从低--->高可以分成下面7个级别

 

PROPAGATION_NEVER

 

  总是非事务地执行,如果存在一个活动事务,则抛出异常

 

PROPAGATION_NOT_SUPPORTED

 总是非事务地执行,并挂起任何存在的事务。

 

PROPAGATION_SUPPORTS

 

 如果没有事务,则非事务的执行。如果存在一个事务,则加入当前事务。

 

PROPAGATION_REQUIRED

 

 如果没有事务,则开启一个新的事务。如果存在一个事务,则加入当前事务。

 

PROPAGATION_NESTED

 如果没有活动事务, 则按PROPAGATION_REQUIRED 属性执行,如果一个活动的事务存在,则运行在一个嵌套的事务中.

 

PROPAGATION_REQUIRES_NEW

 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。

 

PROPAGATION_MANDATORY

 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。

 

【二】PROPAGATION_NESTED PROPAGATION_REQUIRES_NEW的区别:

 

PROPAGATION_REQUIRES_NEW每次开启一个新的事务,同时挂起前一个正在运行的事务,开启的新事务会独立提交/回滚。之后被挂起的前一个事务继续运行,在结束时提交或回滚。

 

由此看来,当使用PROPAGATION_REQUIRES_NEW时,服务层的内部其实是由多个独立的小事务组成的一个大的事务。每个小事务彼此独立,互不影响。一旦内层事务进行了提交,外层事务不能对其进行回滚。而且它需要JTA事务管理器的支持。

 

PROPAGATION_NESTED并不开启新的事务,它使用save point来代替事务,它可以选择在自己的逻辑内回滚,但它不能在自己的逻辑内提交,而必须等到外层的逻辑提交时一并提交。

 

由此看来,当使用PROPAGATION_NESTED时,服务层的内部只有一个事务存在,内嵌的事务回滚不会引起外层的事务回滚(如同上面说的,它可以在自己的逻辑内回滚),但外层的事务回滚会引起内嵌的事务回滚(因为内嵌的事务必须等到外层事务提交时才一并提交)。需要JDBC 3.0以上驱动及1.4以上的JDK版本支持。

 

【三】PROPAGATION_XXX的设置和性能优化

 

一般来说,PROPAGATION_REQUIRED的传播级别就已经够了。对于长时间、可分段的任务,如果也采用一个大的事务一次性提交,则一旦失败代价太大了。最典型的例子就是:大批量的数据导入,你总不能因为一条数据错了而将其它插入全部回滚吧!

 

这时可以考虑划分为小段的PROPAGATION_REQUIRED事务进行,多次独立提交事务。

 

也考虑考虑设置为PROPAGATION_NESTED,因为JDBC 3.0提供了save point机制,可以在事务未提交的情况下保存事务中间的状态,一旦回滚不会回滚全部,而是只回滚到save point(根据时间)。那么我们可以把大的事务划分成多个小的内嵌事务,每个内嵌事务执行成功后刷新save point,如果全部成功则一次性提交,如果中间失败了则回滚则上一个save point,同时继续下一个内嵌事务,不怕将前面尚未提交的其它事务操作全部回滚。

 

PROPAGATION_REQUIRED相比,好处就是事务提交的次数少了,可以一次性写入

=============================================================================-

 

在使用Spring时,大部分会用到他的声明式事务,简单的在配置文件中进行一些规则配置,利用SpringAOP功能就能轻松搞定事务问题;这里面就涉及到一个事务的传播属性问题Propagation,它在TransactionDefinition接口中定义,以供PlatfromTransactionManager使用,PlatfromTransactionManagerspring事务管理的核心接口。

 

  TransactionDefinition

 

  public interface TransactionDefinition {

 

  int getPropagationBehavior();

 

  int getIsolationLevel();

 

  int getTimeout();

 

  boolean isReadOnly();

 

  }

 

  getTimeout()方法,它返回事务必须在多少秒内完成。

 

  isReadOnly(),事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的。

 

  getIsolationLevel()方法返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据。

 

  在TransactionDefinition接口中定义了五个不同的事务隔离级别,ISOLATION_DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应,ISOLATION_READ_UNCOMMITTED 这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。

 

  在TransactionDefinition接口中共有7种选项可用:

 

  PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

 

  PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。

 

  PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。

 

  PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。

 

  PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

 

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

 

  PROPAGATION_NESTED:支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。

 

  现在结合一个实例,应用以上各种传播属性来进行说明:首先声明两个beanServiceAServiceB,其中ServiceB被引用;

 

  ServiceA {

 

  void methodA() {

 

  ServiceB.methodB();

 

  }

 

  }

 

  ServiceB {

 

  void methodB() {

 

  }

 

  }

 

  接下来,我们就一一分析下:

 

  PROPAGATION_REQUIRED

 

  加入当前正要执行的事务不在另外一个事务里,那么就起一个新的事务;比如说,ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED, 那么由于执行ServiceA.methodA的时候, ServiceA.methodA已经起了事务,这时调用ServiceB.methodBServiceB.methodB看到自己已经运行在ServiceA.methodA 的事务内部,就不再起新的事务。而假如ServiceA.methodA运行的时候发现自己没有在事务中,他就会为自己分配一个事务。 这样,在ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务都会被回滚。即使ServiceB.methodB的事务已经被 提交,但是ServiceA.methodA在接下来fail要回滚,ServiceB.methodB也要回滚。

 

  PROPAGATION_SUPPORTS

 

  如果当前在事务中,即以事务的形式运行,如果当前不再一个事务中,那么就以非事务的形式运行。

 

  PROPAGATION_MANDATORY

 

  必须在一个事务中运行。也就是说,他只能被一个父事务调用。否则,他就要抛出异常。

 

  PROPAGATION_REQUIRES_NEW

 

  比如我们设计ServiceA.methodA的事务级别为PROPAGATION_REQUIREDServiceB.methodB的事务级别为PROPAGATION_REQUIRES_NEW 那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的事务,等待ServiceB.methodB的事务完成以后, 他才继续执行。他与PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为ServiceB.methodB是新起一个事务,那么就是存在 两个不同的事务。如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。如果ServiceB.methodB失败回滚, 如果他抛出的异常被ServiceA.methodA捕获,ServiceA.methodA事务仍然可能提交。

 

  PROPAGATION_NOT_SUPPORTED

 

  当前不支持事务。比如ServiceA.methodA的事务级别是PROPAGATION_REQUIRED ,而ServiceB.methodB的事务级别是PROPAGATION_NOT_SUPPORTED 那么当执行到ServiceB.methodB时,ServiceA.methodA的事务挂起,而他以非事务的状态运行完,再继续ServiceA.methodA的事务。 网管联盟bitsCN_com

 

  PROPAGATION_NEVER

 

  不能在事务中运行。假设ServiceA.methodA的事务级别是PROPAGATION_REQUIRED ServiceB.methodB的事务级别是PROPAGATION_NEVER 那么ServiceB.methodB就要抛出异常了。

 

  PROPAGATION_NESTED

 

  理解Nested的关键是savepoint。他与PROPAGATION_REQUIRES_NEW的区别是,PROPAGATION_REQUIRES_NEW另起一个事务,将会与他的父事务相互独立, Nested的事务和他的父事务是相依的,他的提交是要等和他的父事务一块提交的。也就是说,如果父事务最后回滚,他也要回滚的。 Nested事务的好处也是他有一个savepoint

 

  ServiceA {

 

  void methodA() {

 

  try {

 

  ServiceB.methodB();

 

  } catch (Exception e) {

 

  ServiceC.methodC();

 

  }

 

  }

 

  }

 

  也就是说ServiceB.methodB失败回滚,那么ServiceA.methodA会回滚到savepoint点上,ServiceA.methodA可以选择另外一个分支,比如 ServiceC.methodC,继续执行,来尝试完成自己的事务;但是这个事务并没有在EJB标准中定义。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值