`

Spring Transaction 分析事务属性

 
阅读更多

众所周知的ACID属性: 
原子性(atomicity)、一致性(consistency)、隔离性(isolation)以及持久性(durability)。我们无法控制一致性、原子性以及持久性,但可以控制超时,设置事务的只读性以指定隔离级别。 
Spring在TransactionDefinition接口封装了所有这些设置。 

 

TransactionDefinition接口:

 

public interface TransactionDefinition {


	int PROPAGATION_REQUIRED = 0;


	int PROPAGATION_SUPPORTS = 1;

	
	int PROPAGATION_MANDATORY = 2;

	
	int PROPAGATION_REQUIRES_NEW = 3;


	int PROPAGATION_NOT_SUPPORTED = 4;

	
	int PROPAGATION_NEVER = 5;


	int PROPAGATION_NESTED = 6;


	
	int ISOLATION_DEFAULT = -1;


	int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;

	
	int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;


	int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;


	int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;


	int TIMEOUT_DEFAULT = -1;



	int getPropagationBehavior();


	int getIsolationLevel();


	int getTimeout();


	boolean isReadOnly();


	String getName();

}

 

getTimeout:返回一个事务必须完成的时间限制。 

isReadOnly:表示事务是否只读。 

getIsolationLevel:他对其他事务所看到的数据变化进行控制。 
事务隔离级别: 
隔离级别 说明 
ISOLATION_DEFAULT 默认级别(对大多数数据库来说就是ISOLATION_READ_COMMITTED) 
ISOLATION_READ_UNCOMMITTED 最低的隔离级别。事实上我们不应该隔离级别,因为在事务完成前,其他事务可以看到该事务所修改的数据。而在其他事务提交前,该事务也可以看到其他事务所做的修改。 
ISOLATION_READ_COMMITTED 大多数数据库的默认级别。在事务完成前,其他事务无法看到该事务所修改的数据。遗憾的是,在该事务提交后,你就可以查看其他事务插入活更新的数据。这意味着在事务的不同点上,如果其他事务修改数据,你会看到不同的数据。 
ISOLATION_REPEATABLE_READ 该隔离级别确保如果在事务中查询了某个数据集,你至少还能再次查询到相同的数据集,即使其他事务修改了所查询的数据。然而如果其他事务插入了新数据,你就可以查询到该新插入的数据。 
ISOLATION_SERIALIZABLE 代价最大、可靠性最高的隔离级别,所有的事务都是俺顺序一个接一个的执行。 

getPropagationBehavior:指定了当代码请求一个新的事务时Spring所做的事情。 
传播行为指: 
传播行为 说明 
PROPAGATION_REQUIRED 当前如果有事务,Spring就会使用该事务;否则会开始一个新事务。 
PROPAGATION_SUPPORTS 当前如果有事务,Spring就会使用该事务;否则不会开启一个新事务。 
PROPAGATION_MANDATORY 当前如果有事务,Spring就会使用该事务;否则会抛出异常。 
PROPAGATION_REQUIRES_NEW Spring总会开始一个新事务。如果当前有事务,则该事务挂起。 
PROPAGATION_NOT_SUPPORTED Spring不会执行事务中的代码。代码总是在非事务环境下执行,如果当期有事务,则该事务挂起。 
PROPAGATION_NEVER 即使当前有事务,Spring也会在飞事务环境下执行。如果当前有事务,则抛出异常。 
PROPAGATION_NESTED 如果当前有事务,则在嵌套事务中执行。如果没有,那么执行情况与PROPAGATION_REQUIRED一样。

 

TransactionStatus接口:

 

package org.springframework.transaction;

import java.io.Flushable;


public interface TransactionStatus extends SavepointManager, Flushable {


	boolean isNewTransaction();


	boolean hasSavepoint();

	
	void setRollbackOnly();

	
	
	boolean isRollbackOnly();


	@Override
	void flush();

	boolean isCompleted();

}

 

setRollbackOnly:将一个事务表示为不可提交的。

 

PlatformTransactionManager的实现: 

 

package org.springframework.transaction;


public interface PlatformTransactionManager {


	TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

	
	void commit(TransactionStatus status) throws TransactionException;

	
	void rollback(TransactionStatus status) throws TransactionException;

}

 

 


使用TransactionDefinition和TransactionStatus接口,创建并管理事务。
 
DataSourceTransactionManager控制着从DataSource中获得的JDBC Connection上的事务执行; 
HibernateTransactionManager控制着Hibernate session上的事务执行; 
JdoTransactionManager管理着JDO事务; 
JtaTransactionManager将事务管理委托给JTA。

 

JDBC:

 

<!-- 声明事务处理器 -->  
<bean id="transactionManager"  
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
    <property name="dataSource" ref="dataSource"></property>  
</bean>  
  
<!-- 声明事务通知 -->  
<tx:advice id="bookShopTx"  
    transaction-manager="transactionManager">  
    <tx:attributes>  
        <tx:method name="purchase"   
            propagation="REQUIRES_NEW"  
            isolation="READ_COMMITTED"  
            rollback-for="java.lang.ArithmeticException"/>  
    </tx:attributes>  
</tx:advice>  
  
<!-- 声明事务通知需要通知哪些类的那些方法, 即: 那些方法受事务管理 -->  
<aop:config>  
    <!-- 声明切入点 -->  
    <aop:pointcut expression="execution(* cn.partner4java.spring.transaction.BookShopService.*(..))"   
        id="txPointCut"/>  
          
    <!-- 把切入点和事务通知联系起来: 既声明一个增强器 -->  
    <aop:advisor advice-ref="bookShopTx" pointcut-ref="txPointCut"/>  
</aop:config>  

 

 

Hibernate:

 

<bean id="sessionFactory"  
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
    <property name="configLocation" value="classpath:hibernate.cfg.xml"></property>  
    <property name="dataSource" ref="dataSource"></property>      
</bean>  
  
<bean id="transactionManager"  
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
    <property name="sessionFactory" ref="sessionFactory"></property>      
</bean>  
  
<!-- 事务通知 -->  
<tx:advice id="txAdvice" transaction-manager="transactionManager">  
    <tx:attributes>  
        <tx:method name="new*" propagation="REQUIRED" isolation="DEFAULT" />  
        <tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT" />  
        <tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT" />  
        <tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT" />  
        <tx:method name="bulk*" propagation="REQUIRED" isolation="DEFAULT" />  
        <tx:method name="load*" propagation="REQUIRED" isolation="DEFAULT" read-only="true"/>  
        <tx:method name="get*" propagation="REQUIRED" isolation="DEFAULT" read-only="true"/>  
        <tx:method name="query*" propagation="REQUIRED" isolation="DEFAULT" read-only="true"/>  
        <tx:method name="find*" propagation="REQUIRED" isolation="DEFAULT" read-only="true"/>  
        <tx:method name="is*" propagation="REQUIRED" isolation="DEFAULT" read-only="true"/>  
          
        <tx:method name="*" propagation="SUPPORTS" isolation="DEFAULT" />  
    </tx:attributes>  
</tx:advice>  
<aop:config>  
        <aop:advisor pointcut="execution(* *..*service*.*(..))" advice-ref="txAdvice" />  
</aop:config>   
  
<context:component-scan base-package="com.bytter"></context:component-scan>  
  
<tx:annotation-driven/>  

 

JPA:

 

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">  
    <property name="dataSource" ref="dataSource" />  
    <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />  
    <property name="loadTimeWeaver">  
          <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>  
    </property>  
</bean>  
      
  <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">  
       <property name="entityManagerFactory" ref="entityManagerFactory"/>  
  </bean>  
    
  <tx:annotation-driven transaction-manager="transactionManager"/> 

 

 

基于 @Transactional 的声明式事务管理

除了基于命名空间的事务配置方式,Spring 2.x 还引入了基于 Annotation 的方式,具体主要涉及@Transactional 标注。@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。如清单12所示:


清单12. 基于 @Transactional 的事务管理示例配置文件

@Transactional(propagation = Propagation.REQUIRED)
public boolean transfer(Long fromId, Long toId, double amount) {
return bankDao.transfer(fromId, toId, amount);
}

 

Spring 使用 BeanPostProcessor 来处理 Bean 中的标注,因此我们需要在配置文件中作如下声明来激活该后处理 Bean,如清单13所示:


清单13. 启用后处理Bean的配置

<tx:annotation-driven transaction-manager="transactionManager"/>

 

与前面相似,transaction-manager 属性的默认值是 transactionManager,如果事务管理器 Bean 的名字即为该值,则可以省略该属性。

虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 小组建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

基于 <tx> 命名空间和基于 @Transactional 的事务声明方式各有优缺点。基于 <tx> 的方式,其优点是与切点表达式结合,功能强大。利用切点表达式,一个配置可以匹配多个方法,而基于 @Transactional 的方式必须在每一个需要使用事务的方法或者类上用 @Transactional 标注,尽管可能大多数事务的规则是一致的,但是对 @Transactional 而言,也无法重用,必须逐个指定。另一方面,基于 @Transactional 的方式使用起来非常简单明了,没有学习成本。开发人员可以根据需要,任选其中一种使用,甚至也可以根据需要混合使用这两种方式。

如果不是对遗留代码进行维护,则不建议再使用基于 TransactionInterceptor 以及基于TransactionProxyFactoryBean 的声明式事务管理方式,但是,学习这两种方式非常有利于对底层实现的理解。

 

虽然上面共列举了四种声明式事务管理方式,但是这样的划分只是为了便于理解,其实后台的实现方式是一样的,只是用户使用的方式不同而已。

  • 大小: 74.7 KB
分享到:
评论

相关推荐

    spring 事务传播

    系统理解spring事务传播属性,和隔离级别

    Spring + Hibernate + Struts 事务配置小例子(带提示框等小技巧)

    class="org.springframework.transaction.interceptor.TransactionInterceptor"&gt; &lt;!-- 事务拦截器bean需要依赖注入一个事务管理器 --&gt; &lt;!-- 下面定义事务传播属性 [ bus* 事务的方法名]--&gt; *"&gt;...

    高级开发spring面试题和答案.pdf

    @transaction多个数据源事务怎么指定数据源 传播特性有几种?7种; 某一个事务嵌套另一个事务的时候怎么办? REQUIRED_NEW和REQUIRED区别 Spring的事务是如何回滚的,实现原理; 抽象类和接口的区别,什么时候用...

    spring.net中文手册在线版

    14.5.1.理解Spring.NET声明式事务管理的实现 14.5.2.第一个例子 14.5.3.Transaction特性的设置 14.5.4.通过AutoProxyCreator使用声明式事务 14.5.5.通过TransactionProxyFactoryObject使用声明式事务 14.5.6. 通过...

    Spring 2.0 开发参考手册

    9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 插入事务操作 9.5.8. ...

    Spring-Reference_zh_CN(Spring中文参考手册)

    9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.6.1. @Transactional 有关的设置 ...

    Spring中文帮助文档

    9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 事务传播 9.5.8. 通知...

    spring chm文档

    9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 插入事务操作 9.5.8. ...

    Spring API

    9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 事务传播 9.5.8. 通知...

    spring applicationContext 配置文件

    &lt;bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean" p:dataSource-ref="dataSourceProxy"&gt; &lt;value&gt;classpath:SqlMapConfig.xml&lt;/value&gt; &lt;/property&gt; ...

    【分布式事务----LCN】LCN原理及使用方式.docx

    spring.datasource.url=jdbc:mysql://47.92.145.192:3306 /scm_transaction? useUnicode=true&characterEncoding=utf-8&allowMultiQueries =true&useSSL=false spring.datasource.username=db_user2 spring....

    SSH整合&&SSH集成开发

    JTA环境的事务配置 &lt;bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager or WebLogicJtaTransactionManager"/&gt; --&gt; &lt;!-- 使用annotation定义事务 --&gt; ...

    spring3.2+strut2+hibernate4

    -- JTA环境的事务配置 &lt;bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager or WebLogicJtaTransactionManager"/&gt; --&gt; &lt;!-- 使用annotation定义事务 --&gt; ...

    ssh(structs,spring,hibernate)框架中的上传下载

    第11~25行定义了Hibernate的会话工厂,会话工厂类用Spring提供的LocalSessionFactoryBean维护,它注入了数据源和资源映射文件,此外还通过一些键值对设置了Hibernate所需的属性。  其中第16行通过类路径的映射方式...

    SSH第7章上机.zip ACCP8.0

    -- 创建事务管理器(spring针对hibernate实现的事务管理的切面类) --&gt; &lt;bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"&gt; &lt;!-- 事务的通知类型 -...

    维生药业小项目 SSH简单学习项目

    &lt;tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /&gt; &lt;!-- 使用annotation 自动注册bean,并检查@Required,@Autowired的属性已被注入 --&gt; &lt;/beans&gt;

    低清版 大型门户网站是这样炼成的.pdf

    6.3.1 spring 2.5的声明式事务管理 394 6.3.2 基于xml方式的事务管理配置 396 6.3.3 基于annotation方式的事务管理配置 400 6.4 “桃园三结义”——ssh 2组合开发框架始成 404 6.4.1 spring 2.5集成orm中间件...

    OA项目SSH整合框架

    &lt;tx:annotation-driven transaction-manager="transactionManager"/&gt; 2,测试代码 1,Service类 @Service public class InsertUserService { @Resource private SessionFactory ...

    springmvcmybatis

    -- (事务管理)transaction manager, use JtaTransactionManager for global tx --&gt; class="org.springframework.jdbc.datasource.DataSourceTransactionManager"&gt; &lt;!-- 配置事务通知属性 --&gt; ...

    iBATIS实战

    12.5.2 理解Transaction接口 227 12.6 小结 228 第四部分 iBATIS使用秘诀 第13章 iBATIS最佳实践 230 13.1 iBATIS中的单元测试 230 13.1.1 对映射层进行单元测试 231 13.1.2 对DAO进行单元测试 233 13.1.3 对DAO的...

Global site tag (gtag.js) - Google Analytics