Spring--事务小结
2017-04-22 11:25
183 查看
Spring为我们提供了非常方便的事务管理,在不需要了解不同持久层事务处理的情况下,使用配置或注解的方式实现了事务的统一管理。这也就体现了之前所说的Spring核心AOP功能的作用。而为了更好的使用Spring事务管理,需要了解以下知识:
一、数据库事务相关基础知识
1、 何为事务
最简单的话就是,事务内的多个SQL语句,在事务提交时,要么都成功,要么都失败。必定是一个整体。事务的四个特性:
1) 原子性:组成数据库的多个事务操作是一个不可分割的原子单位。若有失败时,已成功的操作也被撤销。
2) 一致性:事务操作成功后,数据库状态和业务规则一致。
3) 隔离性:并发执行数据操作时,不同事务拥有不同的事务空间,互不干扰。
4) 持久性:事务提交成功后,所有数据操作必须持久到数据库内。
2、 数据并发出现的问题
1) 脏读:事务A读取到事务B修改但是未提交的数据。当事务B回滚后,A事务如果以之前读到的数据操作,必定会出错。
2) 不可重复读:事务A读取了两次数据,而这两次数据由于事务B的执行前后不一致。而数据的不一致会导致问题。
3) 幻象读:事务A按照某查询条件读取到数据,这时其他事务新增操作导致新增结果同样满足A的查询条件。事务A再读取时会出现前后数据不一致。
虽然不可重复读和幻象读有相似之处,但是区别在于不可重复读由于数据的更改导致,而幻象读由于新事务提交导致。
丢失更新:
两个事务同时对一个数据操作,在事务互不知道的情况下,其中一个事务的操作可能会被另外一个事务操作覆盖。分为包裹时的回滚覆盖和提交成功的覆盖。
接下来,由于数据库中定义的隔离和Spring事务定义的隔离有重复部分,所以直接介绍Spring的事务属性。
二、Spring事务隔离
定义了当前事务与其他事务的隔离状态。
1、 ISOLATION_DEFAULT:
这是定义的默认隔离级别,自动采用数据库默认的事务隔离级别。
2、 ISOLATION_READ_UNCOMMITED:
这是隔离级别最低的事务隔离。会读取到修改过但是未提交的数据。因此会出现脏读,不可重复读,幻象读。隔离级别在于处理多事务的并发问题。
3、 ISOLATION_READ_COMMITED:
保证不会读取修改过但是未提交的数据。避免了脏读,但是不可重复读和幻象读无法避免。大部分数据库的隔离级别。
4、 ISOLATION_REPEATABLE_READ:
保证不会修改另一个事务读取但未提交的数据,可以避免脏读和不可重复读。但是带来较多的性能损失。
5、 ISOLATION_SERIALIZABLE:
事务串行执行,性能损失最大。
三、Spring事务传播
正常而言,给一个方法定义事务执行是十分清晰的。但是,如果在一个方法中调用了另外一个方法,那么事务操作应该如何执行呢?接下来就是有关事务传播的话题了:
Spring定义了其中类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时如何进行传播:
1、 PROPAGATION_REQUIRED:
如果当前执行有事务,则加入当前事务,若没有事务,则新建一个事务。
例:有ServiceA.methodA,执行时调用ServiceB.methodB。ServiceB.methodB的事务传播属性设为REQUIRED。methodB执行时,先看当前methodA执行环境有没有事
务,如果有,则加入A所在事务,A,B任意方法异常,统一回滚。若没有事务,新建一个事务供B方法执行。
2、 PROPAGATION_SUPPORTS:
如果当前执行有事务,则以事务方式进行。若没有事务,则以非事务方式进行。
3、 PROPAGATION_MANDATORY:
如果当前执行有事务,则以事务方式进行。若没有事务,则抛出异常。
4、 PROPAGATION_REQUIRES_NEW:
无论当前有没有事务,都新建一个事务执行。新建的事务和旧事务分属于两个事务,互不相干。
再以methodA和methodB为例。A如果有事务环境,调用到B方法时,将A所在的事务挂起,B新建一个事务,B执行完后,重新进入A的事务环境。执行过程中,如果A出现
异常,B已经提交,则不用回滚。B出现异常,A方法同样可能提交。
5、 PROPAGATION_NOT_SUPPORTED:
如果当前执行有事务,将事务挂起后继续执行。
6、 PROPAGATION_NEVER:
如果当前执行有事务,将事务挂起后继续执行
7、 PROPAGATION_NESTED:
同样新建一个事务,与REQUIRES_NEW的区别在于,它与父事务是相依的。出现异常时,回滚一致。而且有一个savePoint的选择。
四、Spring事务配置
配置事务大方向有三种:编程式配置(侵入代码较严重,不介绍),XML配置,注解配置。
1、 XML配置:
1) 原始的proxyBean:
以上配置很容易看出是基于动态代理的实现形式。但是需要对每个业务类都进行配置,且只能对方法名定义。而且定义时IDE无法判断输入,容易出错,所以不推荐。
2) 基于tx/aop命名空间:
2、基于注解
只需要在service实现类上增加@Transactional注解,并在Spring配置中
一、数据库事务相关基础知识
1、 何为事务
最简单的话就是,事务内的多个SQL语句,在事务提交时,要么都成功,要么都失败。必定是一个整体。事务的四个特性:
1) 原子性:组成数据库的多个事务操作是一个不可分割的原子单位。若有失败时,已成功的操作也被撤销。
2) 一致性:事务操作成功后,数据库状态和业务规则一致。
3) 隔离性:并发执行数据操作时,不同事务拥有不同的事务空间,互不干扰。
4) 持久性:事务提交成功后,所有数据操作必须持久到数据库内。
2、 数据并发出现的问题
1) 脏读:事务A读取到事务B修改但是未提交的数据。当事务B回滚后,A事务如果以之前读到的数据操作,必定会出错。
2) 不可重复读:事务A读取了两次数据,而这两次数据由于事务B的执行前后不一致。而数据的不一致会导致问题。
3) 幻象读:事务A按照某查询条件读取到数据,这时其他事务新增操作导致新增结果同样满足A的查询条件。事务A再读取时会出现前后数据不一致。
虽然不可重复读和幻象读有相似之处,但是区别在于不可重复读由于数据的更改导致,而幻象读由于新事务提交导致。
丢失更新:
两个事务同时对一个数据操作,在事务互不知道的情况下,其中一个事务的操作可能会被另外一个事务操作覆盖。分为包裹时的回滚覆盖和提交成功的覆盖。
接下来,由于数据库中定义的隔离和Spring事务定义的隔离有重复部分,所以直接介绍Spring的事务属性。
二、Spring事务隔离
定义了当前事务与其他事务的隔离状态。
1、 ISOLATION_DEFAULT:
这是定义的默认隔离级别,自动采用数据库默认的事务隔离级别。
2、 ISOLATION_READ_UNCOMMITED:
这是隔离级别最低的事务隔离。会读取到修改过但是未提交的数据。因此会出现脏读,不可重复读,幻象读。隔离级别在于处理多事务的并发问题。
3、 ISOLATION_READ_COMMITED:
保证不会读取修改过但是未提交的数据。避免了脏读,但是不可重复读和幻象读无法避免。大部分数据库的隔离级别。
4、 ISOLATION_REPEATABLE_READ:
保证不会修改另一个事务读取但未提交的数据,可以避免脏读和不可重复读。但是带来较多的性能损失。
5、 ISOLATION_SERIALIZABLE:
事务串行执行,性能损失最大。
三、Spring事务传播
正常而言,给一个方法定义事务执行是十分清晰的。但是,如果在一个方法中调用了另外一个方法,那么事务操作应该如何执行呢?接下来就是有关事务传播的话题了:
Spring定义了其中类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时如何进行传播:
1、 PROPAGATION_REQUIRED:
如果当前执行有事务,则加入当前事务,若没有事务,则新建一个事务。
例:有ServiceA.methodA,执行时调用ServiceB.methodB。ServiceB.methodB的事务传播属性设为REQUIRED。methodB执行时,先看当前methodA执行环境有没有事
务,如果有,则加入A所在事务,A,B任意方法异常,统一回滚。若没有事务,新建一个事务供B方法执行。
2、 PROPAGATION_SUPPORTS:
如果当前执行有事务,则以事务方式进行。若没有事务,则以非事务方式进行。
3、 PROPAGATION_MANDATORY:
如果当前执行有事务,则以事务方式进行。若没有事务,则抛出异常。
4、 PROPAGATION_REQUIRES_NEW:
无论当前有没有事务,都新建一个事务执行。新建的事务和旧事务分属于两个事务,互不相干。
再以methodA和methodB为例。A如果有事务环境,调用到B方法时,将A所在的事务挂起,B新建一个事务,B执行完后,重新进入A的事务环境。执行过程中,如果A出现
异常,B已经提交,则不用回滚。B出现异常,A方法同样可能提交。
5、 PROPAGATION_NOT_SUPPORTED:
如果当前执行有事务,将事务挂起后继续执行。
6、 PROPAGATION_NEVER:
如果当前执行有事务,将事务挂起后继续执行
7、 PROPAGATION_NESTED:
同样新建一个事务,与REQUIRES_NEW的区别在于,它与父事务是相依的。出现异常时,回滚一致。而且有一个savePoint的选择。
四、Spring事务配置
配置事务大方向有三种:编程式配置(侵入代码较严重,不介绍),XML配置,注解配置。
1、 XML配置:
1) 原始的proxyBean:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 织入对象 --> <bean id="userServiceTarget" class="com.paditang.service.UserService" p:userDao-ref="userDao"> </bean> <!-- 织入生成的代理对象,执行时自动处理业务逻辑 --> <bean id="userService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" p:transactionManager-ref="transactionManager" p:target-ref="userServiceTarget"> <property name="transactionAttributes"> <props> <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean>
以上配置很容易看出是基于动态代理的实现形式。但是需要对每个业务类都进行配置,且只能对方法名定义。而且定义时IDE无法判断输入,容易出错,所以不推荐。
2) 基于tx/aop命名空间:
<aop:config proxy-target-class="true"> <aop:pointcut expression="execution(* com.paditang.service.*.*(..))" id="serviceMethod"/> <aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice"/><!-- 定义切点和增强 --> </aop:config> <tx:advice id = "txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*"/> </tx:attributes> </tx:advice>
2、基于注解
只需要在service实现类上增加@Transactional注解,并在Spring配置中
<!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置基于注解的声明式事务 --> <tx:annotation-driven transaction-manager="transactionManager" />
相关文章推荐
- spring中事务的小结
- Spring 编程式事务和申明式事务选择和使用小结
- 关于spring声明式事务管理异常处理的测试和小结
- 纯JDBC、Hibernate、Spring的AOP声明式事务管理小结
- spring事务和aop问题小结
- 关于spring声明式事务管理异常处理的测试和小结
- Spring 事务 小结
- Spring 编程式事务和申明式事务选择和使用小结
- spring中事务的小结
- spring中事务的小结
- Spring: A Developer's Notebook笔记和小结(4)
- 用 Hibernate 和 Spring 开发事务持久层
- Spring: A Developer's Notebook笔记和小结(1)
- Spring: A Developer's Notebook笔记和小结(6)
- Spring: A Developer's Notebook笔记和小结(10)
- hibernate3.0+ejb3 annotaion配置实战+spring1.21 annotation事务控制
- Spring: A Developer's Notebook笔记和小结(7)
- Spring: A Developer's Notebook笔记和小结(2)
- 用spring管理hibernate事务时,lzay="true"不能用的解决方法
- Spring: A Developer's Notebook笔记和小结(5)