spring 事务

来源:互联网 发布:学生背包品牌知乎 编辑:程序博客网 时间:2024/06/15 09:06

事务有四个特性:ACID

原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作的同时响应。

  一致性(Consistency):一旦事务完成(不管成功或者失败),系统必须确保它所建模的业务处于抑制状态,而不是部分完成部分失败。

隔离性(Isolation):可能有许多事务会同时处理相同的诗句,因此每个事务都会互相隔离,防止数据破坏。

持久性(Durability):一旦事务完成,无论发生什么系统错误,他的结果都能从任何系统崩溃中回复过来。


Spring 事务管理涉及的接口联系如下:

技术分享

Spring 并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给其他平台框架的事务来实现。Spring 事务管理器的接口是:org.springframework.transaction.PlatformTransactionManager,接口内容如下:

Public interface PlatformTransactionManager()...{      TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;     Void commit(TransactionStatus status) throws TransactionException;      Void rollback(TransactionStatus status) throws TransactionException;      } 
从这里可知具体的具体的事务管理机制对Spring来说是透明的,它并不关心那些,那些是对应各个平台需要关心的,所以Spring事务管理的一个优点就是为不同的事务API提供一致的编程模型,如JTA、JDBC、Hibernate、JPA。下面简介各个平台框架实现事务管理的接口:

JDBC:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property name="dataSource" ref="dataSource" /></bean>
Hibernate:

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">        <property name="sessionFactory" ref="sessionFactory" /></bean>
Java持久化API事务(JPA)

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">        <property name="sessionFactory" ref="sessionFactory" /></bean>
Java原生API事务:

 <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">        <property name="transactionManagerName" value="java:/TransactionManager" /></bean>

基本事务属性的定义:

事务管理器接口PlatformTransactionManager通过getTransaction(TransactionDefinition definition)方法来得到事务,这个方法里面的参数是TransactionDefinition类,这个类就定义了一些基本的事务属性。 事务属性包含5个方面如下:

技术分享

TransactionDefinition接口内容如下:

public interface TransactionDefinition {    int getPropagationBehavior(); // 传播行为    int getIsolationLevel(); // 返回事务的隔离级别    int getTimeout();  // 返回事务必须在多少秒内完成    boolean isReadOnly(); // 事务是否只读} 
传播行为(Propagation behavior):

当事务被另一个事务调用时,必须指定事务该如何传播。如:方法可能在现有事务中运行,也可能开启新事务,并在事务中运行。Spring定义了七种传播行为:

PROPAGATION_REQUIRED : 表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务

PROPAGATION_SUPPORTS : 表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行

PROPAGATION_MANDATORY : 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常

PROPAGATION_REQUIRED_NEW :表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager

PROPAGATION_NOT_SUPPORTED : 表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager

PROPAGATION_NEVER : 表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常

PROPAGATION_NESTED : 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务。

隔离级别

隔离级别定义了一个事务可能受其他并发事务影响的程度。

在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务。并发虽然是必须的,但可能会导致一下的问题。

  • 脏读(Dirty reads)——脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。
  • 不可重复读(Nonrepeatable read)——不可重复读发生在一个事务执行相同的查询两次或两次以上(修改),但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。
  • 幻读(Phantom read)——幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据(增删),接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。
隔离级别定义:

ISOLATION_DEFAULT : 使用后端数据库默认的隔离级别

ISOLATION_READ_UNCOMMITTED :最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

ISOLATION_READ_COMMITTED :允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

ISOLATION_REPEATABLE_READ : 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生

ISOLATION_SERIALIZABLE : 最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的

只读

如果事务只对后端的数据库进行该操作,数据库可以利用事务的只读特性来进行一些特定的优化。

事务超时

事务可能涉及对后端数据库的锁定,所以长时间的事务会不必要的占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。

回滚规则

事务五边形的最后一个方面是一组规则,这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚(这一行为与EJB的回滚行为是一致的) 
但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。


事务状态

调用PlatformTransactionManager接口的getTransaction()的方法得到的是TransactionStatus接口的一个实现,这个接口的内容如下:

public interface TransactionStatus{    boolean isNewTransaction(); // 是否是新的事物    boolean hasSavepoint(); // 是否有恢复点    void setRollbackOnly();  // 设置为只回滚    boolean isRollbackOnly(); // 是否为只回滚    boolean isCompleted; // 是否已完成} 

可以发现这个接口描述的是一些处理事务提供简单的控制事务执行和查询事务状态的方法,在回滚或提交的时候需要应用对应的事务状态。


Spring提供了对编程式事务和声明式事务的支持,编程式事务允许用户在代码中精确定义事务的边界,而声明式事务(基于AOP)有助于用户将操作与事务规则进行解耦。 

编程式事务

Spring提供两种方式的编程式事务管理,分别是:使用TransactionTemplate和直接使用PlatformTransactionManager。

使用TransactionTemplate:

采用TransactionTemplate和采用其他Spring模板,如JdbcTempalte和HibernateTemplate是一样的方法。它使用回调方法,把应用程序从处理取得和释放资源中解脱出来。如同其他模板,TransactionTemplate是线程安全的。代码片段:

    TransactionTemplate tt = new TransactionTemplate(); // 新建一个TransactionTemplate    Object result = tt.execute(        new TransactionCallback(){              public Object doTransaction(TransactionStatus status){                  updateOperation();                  return resultOfUpdateOperation();              }      }); // 执行execute方法进行事务管理

使用TransactionCallback()可以返回一个值。如果使用TransactionCallbackWithoutResult则没有返回值。

使用Platform TransactionManger :

    DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); //定义一个某个框架平台的TransactionManager,如JDBC、Hibernate    dataSourceTransactionManager.setDataSource(this.getJdbcTemplate().getDataSource()); // 设置数据源    DefaultTransactionDefinition transDef = new DefaultTransactionDefinition(); // 定义事务属性    transDef.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED); // 设置传播行为属性    TransactionStatus status = dataSourceTransactionManager.getTransaction(transDef); // 获得事务状态    try {        // 数据库操作        dataSourceTransactionManager.commit(status);// 提交    } catch (Exception e) {        dataSourceTransactionManager.rollback(status);// 回滚    }
声明式事务

根据代理机制的不同,总结了五种Spring事务的配置方式,配置文件如下:

(1)每个Bean都有一个代理

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop"    xsi:schemaLocation="http://www.springframework.org/schema/beans           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context-2.5.xsd           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">    <bean id="sessionFactory"             class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">         <property name="configLocation" value="classpath:hibernate.cfg.xml" />         <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />    </bean>     <!-- 定义事务管理器(声明式的事务) -->     <bean id="transactionManager"        class="org.springframework.orm.hibernate3.HibernateTransactionManager">        <property name="sessionFactory" ref="sessionFactory" />    </bean>    <!-- 配置DAO -->    <bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">        <property name="sessionFactory" ref="sessionFactory" />    </bean>    <bean id="userDao"         class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">            <!-- 配置事务管理器 -->            <property name="transactionManager" ref="transactionManager" />            <property name="target" ref="userDaoTarget" />          <property name="proxyInterfaces" value="com.bluesky.spring.dao.GeneratorDao" />        <!-- 配置事务属性 -->         <property name="transactionAttributes">             <props>                 <prop key="*">PROPAGATION_REQUIRED</prop>            </props>         </property>     </bean> </beans>

(2)所有Bean共享一个代理基类

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop"    xsi:schemaLocation="http://www.springframework.org/schema/beans           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context-2.5.xsd           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">    <bean id="sessionFactory"             class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">         <property name="configLocation" value="classpath:hibernate.cfg.xml" />         <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />    </bean>     <!-- 定义事务管理器(声明式的事务) -->     <bean id="transactionManager"        class="org.springframework.orm.hibernate3.HibernateTransactionManager">        <property name="sessionFactory" ref="sessionFactory" />    </bean>    <bean id="transactionBase"             class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"             lazy-init="true" abstract="true">         <!-- 配置事务管理器 -->         <property name="transactionManager" ref="transactionManager" />         <!-- 配置事务属性 -->         <property name="transactionAttributes">             <props>                 <prop key="*">PROPAGATION_REQUIRED</prop>             </props>         </property>     </bean>       <!-- 配置DAO -->    <bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">        <property name="sessionFactory" ref="sessionFactory" />    </bean>    <bean id="userDao" parent="transactionBase" >         <property name="target" ref="userDaoTarget" />      </bean></beans>

(3)使用拦截器

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop"    xsi:schemaLocation="http://www.springframework.org/schema/beans           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context-2.5.xsd           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">    <bean id="sessionFactory"             class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">         <property name="configLocation" value="classpath:hibernate.cfg.xml" />         <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />    </bean>     <!-- 定义事务管理器(声明式的事务) -->     <bean id="transactionManager"        class="org.springframework.orm.hibernate3.HibernateTransactionManager">        <property name="sessionFactory" ref="sessionFactory" />    </bean>     <bean id="transactionInterceptor"         class="org.springframework.transaction.interceptor.TransactionInterceptor">         <property name="transactionManager" ref="transactionManager" />         <!-- 配置事务属性 -->         <property name="transactionAttributes">             <props>                 <prop key="*">PROPAGATION_REQUIRED</prop>             </props>         </property>     </bean>    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">         <property name="beanNames">             <list>                 <value>*Dao</value>            </list>         </property>         <property name="interceptorNames">             <list>                 <value>transactionInterceptor</value>             </list>         </property>     </bean>     <!-- 配置DAO -->    <bean id="userDao" class="com.bluesky.spring.dao.UserDaoImpl">        <property name="sessionFactory" ref="sessionFactory" />    </bean></beans>

(4)使用tx标签配置的拦截器

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:tx="http://www.springframework.org/schema/tx"    xsi:schemaLocation="http://www.springframework.org/schema/beans           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context-2.5.xsd           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">    <context:annotation-config />    <context:component-scan base-package="com.bluesky" />    <bean id="sessionFactory"             class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">         <property name="configLocation" value="classpath:hibernate.cfg.xml" />         <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />    </bean>     <!-- 定义事务管理器(声明式的事务) -->     <bean id="transactionManager"        class="org.springframework.orm.hibernate3.HibernateTransactionManager">        <property name="sessionFactory" ref="sessionFactory" />    </bean>    <tx:advice id="txAdvice" transaction-manager="transactionManager">        <tx:attributes>            <tx:method name="*" propagation="REQUIRED" />        </tx:attributes>    </tx:advice>    <aop:config>        <aop:pointcut id="interceptorPointCuts"            expression="execution(* com.bluesky.spring.dao.*.*(..))" />        <aop:advisor advice-ref="txAdvice"            pointcut-ref="interceptorPointCuts" />           </aop:config>     </beans>

(5)全注解

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:tx="http://www.springframework.org/schema/tx"    xsi:schemaLocation="http://www.springframework.org/schema/beans           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context-2.5.xsd           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">    <context:annotation-config />    <context:component-scan base-package="com.bluesky" />    <tx:annotation-driven transaction-manager="transactionManager"/>    <bean id="sessionFactory"             class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">         <property name="configLocation" value="classpath:hibernate.cfg.xml" />         <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />    </bean>     <!-- 定义事务管理器(声明式的事务) -->     <bean id="transactionManager"        class="org.springframework.orm.hibernate3.HibernateTransactionManager">        <property name="sessionFactory" ref="sessionFactory" />    </bean></beans>

此时在DAO上需加上@Transactional注解,如下:

package com.bluesky.spring.dao;import java.util.List;import org.hibernate.SessionFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.orm.hibernate3.support.HibernateDaoSupport;import org.springframework.stereotype.Component;import com.bluesky.spring.domain.User;@Transactional@Component("userDao")public class UserDaoImpl extends HibernateDaoSupport implements UserDao {    public List<User> listUsers() {        return this.getSession().createQuery("from User").list();    }  }


原创粉丝点击