事务是一个逻辑工作单元,它包括一系列的操作。事务包括4个基本特性(ACID):
1. Atomic(原子性)
事务中包含的操作被看作一个逻辑单元,这个逻辑单元中的操作要么全部成功,要么全部失败。
2. Consistency(一致性)
只有合法的数据可以被写入数据库,如果数据有任何违例(如数据与字段类型不符),则事务应该将其回滚到最初状态。
3. Isolation(隔离性)
事务允许多个用户对同一个数据的并发访问,而不破坏数据的正确性和完整性。同事,并行事务的修改必须与其他并行事务的修改相互独立。
4. Durability(持久性)
事务结束后,事务处理的结果必须能够得到固化。
事务隔离等级
Dirty Reads(脏读)
一个事务读取了另一个并行事务未提交的数据。
Non-repeatable Reads(不可重复读取)
一个事务再次读取之前读取过的数据是,发现该数据已经被另一个已提交的事务修改。
Phantom Reads(虚读)
一个事务重新执一个查询,返回一套符合查询条件的记录,但这些记录汇中包含了因为其他最近提交的书而产生的新记录。
隔离等级 | 脏读 | 不重复读取 | 虚读 |
ISOLATION_READ_UNCOMMITTED | 可能 | 可能 | 可能 |
ISOLATION_READ_COMMITTED | 不可能 | 可能 | 可能 |
ISOLATION_REPEATABLE_READ | 不可能 | 不可能 | 可能 |
ISOLATION_SERIALZABLE | 不可能 | 不可能 | 不可能 |
传播行为(即请求一个新事务时Spring所作的事情)
PROPAGATION_REQUIRED | 当前如果有事务,Spring就会使用该事务;否则会开始一个新事务 |
PROPAGATION_SUPPORTS | 当前如果有事务,Spring就会使用该事务;否则不会开始一个新事务 |
PROPAGATION_MANDATORY | 当前如果有事务,Spring就会使用该事务;否则会抛出异常 |
PROPAGATION_REQUIRES_NEW | Spring总是开始一个新事务。如果当前有事务,则该事务挂起 |
PROPAGATION_NOT_SUPPORTED | Spring不会执行事务中的代码。代码总是在非事务环境下执行,如果当前有事务,则该事务挂起 |
PROPAGATION_NEVER | 即使当前有事务,Spring也会在非事务环境下执行。如果当前有事务,则抛出异常 |
PROPAGATION_NESTED | 如果当前有事务,则在嵌套事务中执行。如果没有,那么执行情况与REQUIRED一样 |
只读提示(Read-only hints)
如果事务只进行读取的动作,则可以利用底层数据库在只读操作时发生的一些最佳化动作,由于这个动作利用到数据库在只读的事务操作最佳化,因而必须在事务中才有效,也就是说要搭配传播行为PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED来设置。
事务超时期间(The transaction timeout period)
有的事务操作可能延续很长一段的时间,事务本身可能关联到数据表格的锁定,因而长时间的事务操作会有效率上的问题,对于过长的事务操作,您要考虑Roll back事务并要求重新操作,而不是无限时的等待事务完成。
您可以设置事务超时期间,计时是从事务开始时,所以这个设置必须搭配传播行为PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED来设置。
两种Spring事务管理方式:编程式、声明式。
Spring提供两种方式的编程式事务管理,分别是:使用TransactionTemplate和直接使用PlatformTransactionManager。
Spring也提供声明式事务管理。这是通过AOP实现的。大多数Spring用户选择声明式事务管理,这是最少影响应用代码的选择,因而这是和非侵入性的轻量级容器的观念是一致的。
1)通常通过TransactionProxyFactoryBean设置Spring事务代理。需要一个目标对象包装在事务代理中。这个目标对象一般是一个普通Javabean。当我们定义TransactionProxyFactoryBean时,必须提供一个相关的 PlatformTransactionManager的引用和事务属性。事务属性含有事务定义。例如:
<bean id="transactionService"class="org.springframework. transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref local="transactionManager"/>
</property>
<property name="target">
<ref local="transactionServiceControl"/>
</property>
<property name="transactionAttributes">
<props>
<prop key=”insert*”>PROPAGATION_REQUIRED</prop>
<prop key=”update*”>PROPAGATION_REQUIRED</prop>
<prop key=”*”>PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
2)另一种声明方式
<bean id="bankService"
class="com.apress.prospring2.ch16.services.DefaultBankService">
<property name="accountDao" ref="accountDao"/>
</bean>
<bean id="transactionManager"
class="org.springFramework.jdbc.datasource.DataSourceTransactionManager">
<property name="sessionFactory" ref=" sessionFactory "/>
</bean>
<aop:config>
<aop:pointcut id="allServiceMethods"
expression="execution(* com.apress.prospring2.ch16.services.*.*(..))"/>
<aop:advisor advice-ref="defaultTransactionAdvice"
pointcut-ref="allServiceMethods"/>
</aop:config>
<tx:advice id="defaultTransactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method
name="*"
isolation="DEFAULT"
propagation="REQUIRED"
no-rollback-for="java.lang.RuntimeException"
timeout="100"/>
<tx:method
name="get*"
read-only="true"/>
</tx:attributes>
</tx:advice>