关于spring的事务传播特性
我们都知道事务的概念,那么事务的传播特性是什么呢?(此处着重介绍传播特性的概念,关于传播特性的相关配置就不介绍了,可以查看spring的官方文档)
在我们用SSH开发项目的时候,我们一般都是将事务设置在Service层 那么当我们调用Service层的一个方法的时候它能够保证我们的这个方法中执行的所有的对数据库的更新操作保持在一个事务中,在事务层里面调用的这些方法要么全部成功,要么全部失败。那么事务的传播特性也是从这里说起的。
如果你在你的Service层的这个方法中,除了调用了Dao层的方法之外,还调用了本类的其他的Service方法,那么在调用其他的 Service方法的时候,这个事务是怎么规定的呢,我必须保证我在我方法里掉用的这个方法与我本身的方法处在同一个事务中,否则如果保证事物的一致性。事务的传播特性就是解决这个问题的,“事务是会传播的”在Spring中有针对传播特性的多种配置我们大多数情况下只用其中的一种:PROPGATION_REQUIRED:这个配置项的意思是说当我调用service层的方法的时候开启一个事务(具体调用那一层的方法开始创建事务,要看你的aop的配置),那么在调用这个service层里面的其他的方法的时候,如果当前方法产生了事务就用当前方法产生的事务,否则就创建一个新的事务。这个工作使由Spring来帮助我们完成的。
以前没有Spring帮助我们完成事务的时候我们必须自己手动的控制事务,例如当我们项目中仅仅使用hibernate,而没有集成进 spring的时候,我们在一个service层中调用其他的业务逻辑方法,为了保证事物必须也要把当前的hibernate session传递到下一个方法中,或者采用ThreadLocal的方法,将session传递给下一个方法,其实都是一个目的。现在这个工作由 spring来帮助我们完成,就可以让我们更加的专注于我们的业务逻辑。而不用去关心事务的问题。
默认情况下当发生RuntimeException的情况下,事务才会回滚,所以要注意一下 如果你在程序发生错误的情况下,有自己的异常处理机制定义自己的Exception,必须从RuntimeException类继承 这样事务才会回滚!
Spring事务传播特性总结:
1.只要定义为spring的bean就可以对里面的方法使用@Transactional注解。
2.Spring的事务传播是Spring特有的。不是对底层jdbc的代理。
3.使用spring声明式事务,spring使用AOP来支持声明式事务,会根据事务属性,自动在[方法调用之前决定是否开启一个事务],并在[方法执行之后]决定事务提交或回滚事务。
4.Spring支持的PROPAGATION_NESTED 与PROPAGATION_REQUIRES_NEW的区别:
PROPAGATION_REQUIRES_NEW:二个事务没有信赖关系,不会存在A事务的成功取决于B事务的情况。有可能存在A提交B失败。A失败(比如执行到doSomeThingB的时候抛出异常)B提交,AB都提交,AB都失败的可能。
PROPAGATION_NESTED:与PROPAGATION_REQUIRES_NEW不同的是,内嵌事务B会信赖A。即存在A失败B失败。A成功,B失败。A成功,B成功。而不存在A失败,B成功。
5. 特别注意PROPAGATION_NESTED的使用条件:使用JDBC 3.0驱动时,仅仅支持DataSourceTransactionManager作为事务管理器。需要JDBC 驱动的java.sql.Savepoint类。有一些JTA的事务管理器实现可能也提供了同样的功能。使用PROPAGATION_NESTED,还需要把PlatformTransactionManager的nestedTransactionAllowed属性设为true;而 nestedTransactionAllowed属性值默认为false;
6.特别注意PROPAGATION_REQUIRES_NEW的使用条件:JtaTransactionManager作为事务管理器
的AOP简介与事务传播特性总结2009-10-26 16:56srping用到的另外一项技术就是AOP(Aspect-Oriented Programming, 面向切面编程),它是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程)的补充。AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点。在应用 AOP 编程时, 仍然需要在定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里。每个事物逻辑位于一个位置, 代码不分散,便于维护和升级,业务模块更简洁, 只包含核心业务代码。
现实中使用spring最多的就是声明式事务配置功能。下面就来了解其aop在事务上应用。首先要了解的就是AOP中的一些概念:
Aspect(切面):指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面是横切性关注点的抽象。
joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点,实际上joinpoint还可以是field或类构造器)。
Pointcut(切入点):所谓切入点是指我们要对那些joinpoint进行拦截的定义。
Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知。
Target(目标对象):代理的目标对象。
Weave(织入):指将aspects应用到target对象并导致proxy对象创建的过程称为织入。
Introduction(引入):在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field。
所谓AOP,我的理解就是应该是这样一个过程,首先需要定义一个切面,这个切面是一个类,里面的方法就是关注点(也是通知),或者说里面的方法就是用来在执行目标对象方法时需要执行的前置通知,后置通知,异常通知,最终通知,环绕通知等等。有了切面和通知,要应用到目标对象,就需要定义这些通知的切入点,换句话说就是需要对哪些方法进行拦截,而这些被拦截的方法就是连接点,所谓连接点也就是在动态执行过程,被织入切面的方法(至少在spring中只能对方法进行拦截)。因此,在动态过程中通知的执行就属于织入过程,而被织入这些通知的对象就是目标对象了。
通常应用中,被织入的都是事务处理,对事务的织入不是普通简单的织入,它有着事务特有的特性——
事务的传播特性:
1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务。如果没有事务则开启新的事物。
2. PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。
3. PROPAGATION_MANDATORY: 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
4. PROPAGATION_REQUIRES_NEW: 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
5. PROPAGATION_NOT_SUPPORTED: 总是非事务地执行,并挂起任何存在的事务。
6. PROPAGATION_NEVER: 总是非事务地执行,如果存在一个活动事务,则抛出异常
7.(spring)PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。
这些都是事务特有的特性,比如前面分析的,如果两个在代码上不相关的操作,需要放在同一个事务中,这就需要利用到传播特性了,这时后调用的方法的传播特性的值就应该是PROPAGATION_REQUIRED。在spring中只需要进行这样的配置,就实现了生命式的事物处理。
化成表格的事务的传播特性
事务属性 |
事务1 |
事务2 |
Required |
无 事务1 |
事务2 事务1 |
RequiredNew |
无 事务1 |
事务2 事务2 |
Support |
无 事务1 |
无 事务1 |
Mandatory |
无 事务1 |
抛异常 事务1 |
NOSupport |
无 事务1 |
无 无 |
Never |
无 事务1 |
无 抛异常 |
最后一点需要提及的就是Spring事务的隔离级别:
1. ISOLATION_DEFAULT:这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。
2. ISOLATION_READ_UNCOMMITTED:这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。
3. ISOLATION_READ_COMMITTED:保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
4. ISOLATION_REPEATABLE_READ:这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。
除了第一个是spring特有的,另外四个与JDBC的隔离级别相对应。第二种隔离级别会产生脏读,不可重复读和幻像读,特别是脏读,一般情况下是不允许的,所以这种隔离级别是很少用到的。大多说数据库的默认格里基本是第三种。它能消除脏读,但是可重复读保证不了。第四种隔离级别也有一些数据库作为默认的隔离级别,比如MySQL。最后一种用的地方不多,除非是多数据访问的要求特别高,否则轻易不要用它,因为它会严重影响数据库的性能