您的位置:首页 > 编程语言 > Java开发

spring 事务总结

2007-12-20 12:45 218 查看
以往我们需要事务控制的时候,通常需要引入笨重的EJB,Spring的出现改变了这种状况,我们可以用Spring的轻量级容器来管理事务。Spring对事务的控制有几种方式:
1.编码的方式


class CourseServiceImpl




...{


public void enrollStudentInCourse()




...{


transactionTemplate.execute(


new TransactionCallback()




...{


public Object doInTransaction(TransactionStatus ts)




...{




try...{


// do staff




}catch(Exception e)...{


ts.setRollbackOnly();


}


return null;//如果成功,事务被提交


}


}


);


}


}



transactionTemplate实例是从那里来的呢?他将被注入到CourseServiceImpl,代码如下:


<bean id="transactionTemplate" class=""org.springframework.transaction.support.TransactionTemplate">


<property name="transactionManager">


<ref bean="transactionManager"/>


</property>


</bean>


<bean id="courseService" class="com.springinaction.training.service.CourseServiceImpl">


<property name="transactionTemplate">


<ref bean="transactionTemplate"/>


</property>


</bean>

通常,你的事务的需求并没有要求在事务的边界上进行如此精确的控制,这就是我们一般选择在应用代码之外声明事务的原因。
2.声名的方式
在Spring里,事务属性是对事务策略如何应用到方法的描述,这个描述包括下列一个或多个参数:
l 传播行为
l 隔离级别
l 只读提示
l 事务超时间隔
事务的传播行为主要包含以下几个:
Ø PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
Ø PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
Ø PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
Ø PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
Ø PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
Ø PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
关于事务的传播行为,具体可以参照http://fhjxp.javaeye.com/blog/124978,写的比较详细。
关于事务的隔离级别:
Isolation Level(事务隔离等级):
1、Serializable:最严格的级别,事务串行执行,资源消耗最大;
2、REPEATABLE READ:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。
3、READ COMMITTED:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。
4、Read Uncommitted:保证了读取过程中不会读取到非法数据。
隔离级别在于处理多事务的并发问题。
我们知道并行可以提高数据库的吞吐量和效率,但是并不是所有的并发事务都可以并发运行,这需要查看数据库教材的可串行化条件判断了。
这里就不阐述。
我们首先说并发中可能发生的3中不讨人喜欢的事情
1: Dirty reads--读脏数据。也就是说,比如事务A的未提交(还依然缓存)的数据被事务B读走,如果事务A失败回滚,会导致事务B所读取的的数据是错误的。
2: non-repeatable reads--数据不可重复读。比如事务A中两处读取数据-total-的值。在第一读的时候,total是100,然后事务B就把total的数据改成200,事务A再读一次,结果就发现,total竟然就变成200了,造成事务A数据混乱。
3: phantom reads--幻象读数据,这个和non-repeatable reads相似,也是同一个事务中多次读不一致的问题。但是non-repeatable reads的不一致是因为他所要取的数据集被改变了(比如total的数据),但是phantom reads所要读的数据的不一致却不是他所要读的数据集改变,而是他的条件数据集改变。比如Select account.id where account.name="ppgogo*",第一次读去了6个符合条件的id,第二次读取的时候,由于事务b把一个帐号的名字由"dd"改成"ppgogo1",结果取出来了7个数据。
Dirty reads non-repeatable reads phantom reads
Serializable 不会 不会 不会
REPEATABLE READ 不会 不会 会
READ COMMITTED 不会 会 会
Read Uncommitted 会 会 会
readOnly:
事务属性中的readOnly标志表示对应的事务应该被最优化为只读事务。这是一个最优化提示。在一些情况下,一些事务策略能够起到显著的最优化效果,例如在使用Object/Relational映射工具(如:Hibernate或TopLink)时避免dirty checking(试图“刷新”)。
Timeout :
在事务属性中还有定义“timeout”值的选项,指定事务超时为几秒。在JTA中,这将被简单地传递到J2EE服务器的事务协调程序,并据此得到相应的解释。

以上所阐述的为基础部分,下面我们看看Spring声明事务的策略有那几种!
l TransactionProxyFactoryBean参照一个方法的事务属性,决定如何在那个方法上执行事务策略,但是TransactionProxyFactoryBean从哪里得到一个方法的事务特性呢?TransactionProxyFactoryBean有一个transactionAttributeSource属性,这个属性被设置成一个transactionAttributeSource的实例,transactionAttributeSource是作为在方法上查找事务属性的一个参考。




<bean id="transactionAttributeSource" class="org.springframework.transaction.inteceptor.MatchAlwaysTransactionAttributeSource">


</bean>

MatchAlwaysTransactionAttributeSource可能是最简单的TransactionAttributeSource的实现,它每一次调用它的getTransactionAttribute()方法被调用过,它总是简单的返回相同的TransactionAttribtue,而不管这个事务包含了什么方法(PROPAGATION_REQUIRED和ISOLATION_DEFAULT)。那就是MatchAlwaysTransactionAttributeSource永远匹配在起作用;同时你也可以改变默认的事务属性:




<bean id="myTransactionAttribute" class="org.springframework.transaction.interceptor.DefaultTransactionAttribute">


<property name="propagationBehaviorName">


<value>PROPAGATION_REQUIRED_NEW</value>


</property>


<property name="isolationLevelName">


<value>ISOLATION_REPEATABLE_READ</value>


</property>


</bean>


<bean id="transactionAttributeSource" class="org.springframework.transaction.inteceptor.MatchAlwaysTransactionAttributeSource">


<property name="transactionAttribute">


<ref bean="myTransactionAttribute"/>


</property>


</bean>

l 通过方法名声名事务
类似与EJB中的CMT,也就是CMT等价物。




<bean id="transactionAttributeSource" class="org.springframework.transaction.inteceptor.NameMatchTransactionAttributeSource">


<properties name="properties">


<props>


<prop key="get*">


PROPAGATION_REQUIRED_NEW


</prop>


</props>


</properties>


</bean>

3. 用元数据声明事务(少用)
实际在项目中用到的配置为:


<bean id="transactionInterceptor"


class="org.springframework.transaction.interceptor.TransactionInterceptor">


<property name="transactionManager" ref="transactionManager"/>


<property name="transactionAttributes">


<props>


<prop key="save*">PROPAGATION_REQUIRED,-JbssAppException</prop>


<prop key="remove*">PROPAGATION_REQUIRED,-JbssAppException</prop>


<prop key="update*">PROPAGATION_REQUIRED,-JbssAppException</prop>


<prop key="create*">PROPAGATION_REQUIRED,-JbssAppException</prop>


<prop key="delete*">PROPAGATION_REQUIRED,-JbssAppException</prop>


<prop key="add*">PROPAGATION_REQUIRED,-JbssAppException</prop>


<prop key="get*">PROPAGATION_REQUIRED,readOnly,-JbssAppException</prop>


<prop key="find*">PROPAGATION_REQUIRED,readOnly,-JbssAppException</prop>


</props>


</property>


</bean>


<bean id="manager" parent="txProxyTemplate">


<property name="target">


<bean class="com.jbss.service.base.impl.BaseManagerImpl">


<property name="dao" ref="dao" />


</bean>


</property>


</bean>


<bean id="log" class="com.jbss.util.LogAdvice"/>


<bean id="txProxyTemplate" class="org.springframework.aop.framework.ProxyFactoryBean">


<property name="interceptorNames">


<list>


<value>log</value>


<value>transactionInterceptor</value>


</list>


</property>


</bean>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: