spring的事务支持
spring提供事务支持,有声明式事务和程序控制事务。
声明式事务,提供基本的事务支持。
以Hibermate为例
<bean id ="transacrtionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" /> //sessionFactory是配置的数据会话工厂
</bean>
spring的声明是事务是通过AOP框架来实现的。
定义声明式事务,需要五个参数,虽然Spring提供了几种声明式事务机制,但是他们都依靠以下5个参数来控制如何管理事务策略
分别是Propagation,Isolation,Rollback Rules ,Timeout, Read-Only
Propagation:传播行为
事务的第一个方面是传播行为,传播行为定义关于客户端和被调用方法的事务边界。
传播行为回答了这样的一个问题,就是一个新的事务应该被启动还是被挂起,或者是一个方法是否应该在事务性上下文中运行。
传播行为 | 意义 |
PROPAGATION_MANDATORY | 表示该方法必须运行在一个事务中,如果当前没有事务正在发生,将抛出一个异常 |
PROPAGATION_NESTED | 表示如果当前正有一个事务进行中,则该方法应当运行在一个嵌套式事务中,被嵌套的事务可以独立进行提交或回滚,如果封装事务不存在,行为就像PROPAGATION_REQUIRED一样。 |
PROPAGATION_NEVER | 表示当前方法不应该在一个事务性上下文中运行,如果当前正有一个事务正在运行,抛出一个异常 |
PROPAGATION_NOT_SUPPORTED | 表示该方法不应该在一个事务中运行,如果一个现有的事务正在进行,则它会在进行期间被挂起 |
PROPAGATION_REQUIRED | 表示当前方法必须在一个事务中运行,如果一个现有的事务正在进行,该方法会在那个事务中运行,否则,会开启一个新的事务 |
PROPAGATION_REQUIRES_NEW | 表示当前方法必须在他自己的事务中运行,一个新的事务将被启动,而且如果有一个现有事务正在运行的化,则将在这个方法运行期间被挂起。 |
PROPAGATION_SUPPORTS | 表示当前方法不需要事务性上下文,但是如果有一个事务已经在运行的话,它也可以在这个事务里运行。 |
Propagation:隔离级别
在一个典型的应用程序中,多个事务同事进行,经常会为了完成各自的工作而操作同一个数据—— 并发,虽然这是必须的,但是会导致以下的问题。
* 脏读:脏读发生在一个事务读取了另一个事务改写但是还没有的提交的数据时。如果另一个事务在稍后发生了回滚,那么读取的数据就完全无效了。
*不可重复读:不可重读读发生在一个事务执行相同查询两次或两次以上,但是每次查询结果都不同时,这通常是由于另一个并发事务在两次查询之间更新了数据。
*幻读:幻读和不可重复读相似,当一i个事务读取几行记录后,另一个并发事务插入了一些数据时,记录就发生了,再后来的查询中,第一个事务机会发现一些原来没有的数据。
在理想状态下,事务之间将完全隔离,但是完全格式会以性能为代价。
隔离级别 | 含义 |
IOSLATION_DEFAULT | 使用后端数据库默认的隔离级别 |
IOSLATION_READ_UNCOMMITTED | 允许读取尚未提交的数据,可能会导致脏读,不可重复读,幻读等问题。 |
IOSLATION_READ_COMMITTED | 允许读取并行事务已经提交的数据,防止了脏读,当时仍有可能不可重复读,幻读的问题。 |
IOSLATION_REPEATABLE_READ | 对相同字段的多次读取的结果是一致,除非数据是当前事务改变,可以防止脏读和不可重复读,但是幻读仍有可能发生 |
IOSLATION_SERIALIZABLE | 隔离界别最高的,也是i性能最低的。完全服从ACID(1)的隔离级别。因为他是通完完全锁定当前事务的数据表来完成的 |
*(1) : ACID 事务的四个特性原子性,一致性,隔离性,持久性
Read_Only:只读
如果一个事务只对数据库执行读操作,那么该数据库就可能可以利用那个事务的只读特性,采取某些优化措施。
由于只读的优化措施时在一个事务启动时,由后端数据库实施的,因此,对于那些具有可能启动一个新事物的传播行为的方法来说,将事务声明为只读才有意义。
Timeout:事务超时
对于长时间事务,确保不会让事务对后端数据库进行锁定,超时自动回滚。
Rollback Rules:回滚规则
它定义事务在哪些异常下回滚,那些异常下不回滚,默认情况下,出现异常时,就会回滚。
在spring2.0之前,声明式事务管理通过使用spring的TransactionProxyFactoryBean代理POJO来完成 ,以rantService为列
<bean id="rantService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="target" class="rantServiceTarget"/> //配置事务目标
<property name="proxyInterfaces" value="com.roadtantz.service.RantService"/> //指定代理接口
<property name="transactionManager" ref="transactionManager"/> //装配进事务管理器
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIRED,readOnly</prop> //配置事务边界
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
红色标出的id名为rantService 这不于实际的rantService Bean命名冲突了吗?
并没有
因为这里生成的代理对象,在客户端请求rant服务时,实际调用的代理对象,TransactionProxyFactoryBean生成的代理伪装成了真正的rant服务,真正的Bean配置
<bean id="rantServiceTarget"
class="com.roadtantz.service.impl.RantServiceImpl">
</bean>
注入中的transactionManager属性时事务管理器,可以根据需要使用任意一种管理器,距离使用支持Hibernate的事务管理器
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernatrTransactionManager">
<property name="sessionFactory" ref="sessionFactory"> //配置的数据库会话工厂
</bean>
transactionAttributes属性声明哪些方法将在事务内运行,以及相应的事务参数是什么。prop中的值都用逗号分隔,
传播行为+隔离级别+只读+回滚规则
PROPAGATION+IOSLATION+readOnly+Rollback Rule
其中传播行为是唯一必须的要素