spring学习笔记(4)-事务
Spring的Dao框架对事务提供了强大的支持。它包括有两种事务管理,即:
1。编程式事务管理(programmatic tansaction management)
2。声明式事务管理(Declarative tansaction management)
所谓编程式事务管理,就是把事务管理以代码的形式编写到你的应用中要使用事务管理的地方,灵活性较强。而声明式事务管理是以配置文件的形式在xml文件中定义,好处是不具有代码入侵性,当不需要事务管理时,可以直接修改配置文件,而不用修改代码。
在Spring中,主要涉及以下几种事务属性:
1. 传播行为(propagation behavior)
它是对事务的起始,暂停,终止时刻的定义,主要有以下几种
参数 含义
PROPAGATION_REQUIRED 如果存在事务的话,就继续这个事务,如果不存在,新建一个事务。
PROPAGATION_SUPPORTS 如果存在事务的话,就继续这个事务,如果不存在,就以非事务的方式进行。
PROPAGATION_MANDATORY 必须在现存事务中执行,否则抛出异常。
PROPAGATION_REQUIRES_NEW 建立一个新事务,如果现存一个事务,则暂停它。
PROPAGATION_NOT_SUPPORTED 不再事务中执行,如果现存事务,则暂停它。
PROPAGATION_NEVER 不再事务中执行,如果现存事务,则抛出异常。
PROPAGATION_NESTED 在一个嵌入的事务中执行,否则同PROPAGATION_REQUIRED
上述参数是在org.springframework.transaction.TransactionDefinition接口中定义的(类型是public static final,值从0到6)。上述参数中最常用的是PROPAGATION_REQUIRED。
2. 隔离等级(isolation level)
在一个应用应用程序中,可能有多个事务在运行,这时就会产生一些问题。
?dirty read
一个事务更新了数据库中的某些数据,另一个事务读取了这些数据,这时前一个事务由于某些原因回滚了,那么第二个事务读取的数据就是“脏数据”。
?non-repeatable read
一个事务需要两次查询同一数据,但两次查询中间可能有另外一个事务更改了这个数据,导致前一个事务两次读出的数据不一致。
?phantom read
一个事务两次查询同一个表,但两次查询中间可能有另外一个事务又向这个表中插入了一些新数据,导致前一个事务的两次查询不一致。
为了解决以上问题,Spring的事务管理定义了一些隔离级别,所谓“隔离”,即对数据的锁定。
参数 含义
ISOLATION_DEFAULT 使用数据库默认的隔离级别
ISOLATION_READ_UNCOMMITTED 容许事务读取其他并行事务还未提交的数据。这种级别会出现上面三种情况。
ISOLATION_READ_COMMITTED 容许事务读取其他并行事务已经提交(commit)的数据,可防止dirty read
ISOLATION_REPEATABLE_READ 这种级别会可以防止上面三种情况发生。
ISOLATION_SERIALIZABLE 使用事务锁,锁定相应数据,可以防止上面三种情况发生,但效率比较低。
上述参数也是在org.springframework.transaction.TransactionDefinition接口中定义的(类型是public static final,值为-1,1,2,4,8)。上述参数中最常用的是ISOLATION_DEFAULT。
3. read only
应用这项属性时,底层的数据库可以对读取进行最优化,但要配合PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW或PROPAGATION_NESTED使用,即只能在事务中使用。
4. timeout
在多事务并行情况下,为了保证正确性,有些事务的操作会有延迟,甚至死锁。设置事务超时时间,可以避免事务的长时间等待。设置事务超时时间也要配合PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW或PROPAGATION_NESTED使用。
以上的四种属性及其相应方法都定义在org.springframework.transaction.TransactionDefinition接口及其实现类(如org.springframework.transaction.support.DefaultTransactionDefinition)里。
下面来看下声明式事务管理:
在理解Spring的声明式事务管理方面最重要的概念是:Spring的事务管理是通过AOP代理实现的。其中的事务通知由元数据(目前基于XML或注解)驱动。代理对象与事务元数据结合产生了一个AOP代理,它使用一个PlatformTransactionManager实现品配合TransactionInterceptor,在方法调用前后实施事务。 如果对spring aop 不怎么理解的可以看看我的第一篇关于spring AOP的介绍http://langxiashahai.iteye.com/admin/blogs/707480
可以通过下面的例子了解(spring2.0以后版本的写法):
那么可以对这个文件进行简单的分析:
想施加的事务语义封装在<tx:advice/>定义中,把所有方法看作执行在只读事务上下文中(当然可以用*占位符对其他get、update、delete。。。。方法进行设置)。其中的 'transaction-manager' 属性被设置为一个指向 PlatformTransactionManager bean的名字(这里指 transactionManager),该bean将实际上实施事务管理。
<aop:config/>确保由 'txAdvice' bean定义的事务通知在应用中合适的点被执行,首先我们用aop:pointcut定义了一个切面,它匹配 org.tink.service.imp 包下面所有接口定义的所有操作,我们把该切面叫做 interceptorPointCuts。然后我们用一个通知器aop:advisor 把这个切面与 'txAdvice' 绑定在一起,表示当 interceptorPointCuts 执行时,'txAdvice' 定义的通知逻辑将被执行。
不过在web应用程序中大多推荐使用声明式事务管理。