现在的位置: 首页 > 综合 > 正文

spring 事务总结

2017年10月19日 ⁄ 综合 ⁄ 共 6336字 ⁄ 字号 评论关闭

以往我们需要事务控制的时候,通常需要引入笨重的EJBSpring的出现改变了这种状况,我们可以用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:最严格的级别,事务串行执行,资源消耗最大;

2REPEATABLE READ:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了脏读取不可重复读取的情况,但是带来了更多的性能损失。

3READ COMMITTED:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了脏读取。该级别适用于大多数系统。

4Read Uncommitted:保证了读取过程中不会读取到非法数据。

隔离级别在于处理多事务的并发问题。
我们知道并行可以提高数据库的吞吐量和效率,但是并不是所有的并发事务都可以并发运行,这需要查看数据库教材的可串行化条件判断了。
这里就不阐述。
我们首先说并发中可能发生的3中不讨人喜欢的事情
1
   Dirty reads--读脏数据。也就是说,比如事务A的未提交(还依然缓存)的数据被事务B读走,如果事务A失败回滚,会导致事务B所读取的的数据是错误的。

2   non-repeatable reads--数据不可重复读。比如事务A中两处读取数据-total-的值。在第一读的时候,total100,然后事务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映射工具(如:HibernateTopLink)时避免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_REQUIREDISOLATION_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>

抱歉!评论已关闭.