Spring 事务管理

Spring 事务管理

事务管理

一个数据库事务是一个被视为单一的工做单元的操做序列。这些操做应该要么完整地执行,要么彻底不执行。事务管理是一个重要组成部分,RDBMS 面向企业应用程序,以确保数据完整性和一致性。事务的概念能够描述为具备如下四个关键属性说成是 ACIDhtml

  • 原子性:事务应该看成一个单独单元的操做,这意味着整个序列操做要么是成功,要么是失败的。java

  • 一致性:这表示数据库的引用完整性的一致性,表中惟一的主键等。mysql

  • 隔离性:可能同时处理不少有相同的数据集的事务,每一个事务应该与其余事务隔离,以防止数据损坏。spring

  • 持久性:一个事务一旦完成所有操做后,这个事务的结果必须是永久性的,不能因系统故障而从数据库中删除。

一个真正的 RDBMS 数据库系统将为每一个事务保证全部的四个属性。使用 SQL 发布到数据库中的事务的简单视图以下:sql

  • 使用 begin transaction 命令开始事务。数据库

  • 使用 SQL 查询语句执行各类删除、更新或插入操做。express

  • 若是全部的操做都成功,则执行提交操做,不然回滚全部操做。

编程式 vs. 声明式

Spring 支持两种类型的事务管理:编程

  • 编程式事务管理 :这意味着你在编程的帮助下有管理事务。这给了你极大的灵活性,但却很难维护。url

  • 声明式事务管理 :这意味着你从业务代码中分离事务管理。你仅仅使用注释或 XML 配置来管理事务。

Spring 事务抽象

Spring 事务抽象的关键是由 org.springframework.transaction.PlatformTransactionManager 接口定义,以下所示:spa

public interface PlatformTransactionManager {
   TransactionStatus getTransaction(TransactionDefinition definition);
   throws TransactionException;
   void commit(TransactionStatus status) throws TransactionException;
   void rollback(TransactionStatus status) throws TransactionException;
}

接口方法描述

序号 方法 & 描述
1

TransactionStatus getTransaction(TransactionDefinition definition)

根据指定的传播行为,该方法返回当前活动事务或建立一个新的事务。

2

void commit(TransactionStatus status)

该方法提交给定的事务和关于它的状态。

3

void rollback(TransactionStatus status)

该方法执行一个给定事务的回滚。

TransactionDefinition 是在 Spring 中事务支持的核心接口,它的定义以下:

public interface TransactionDefinition {
   int getPropagationBehavior();
   int getIsolationLevel();
   String getName();
   int getTimeout();
   boolean isReadOnly();
}
序号 方法 & 描述
1

int getPropagationBehavior()

该方法返回传播行为。Spring 提供了与 EJB CMT 相似的全部的事务传播选项。

2

int getIsolationLevel()

该方法返回该事务独立于其余事务的工做的程度。

3

String getName()

该方法返回该事务的名称。

4

int getTimeout()

该方法返回以秒为单位的时间间隔,事务必须在该时间间隔内完成。

5

boolean isReadOnly()

该方法返回该事务是不是只读的。

下面是隔离级别的可能值:

序号 隔离 & 描述
1

TransactionDefinition.ISOLATION_DEFAULT

这是默认的隔离级别。

2

TransactionDefinition.ISOLATION_READ_COMMITTED

代表可以阻止误读;能够发生不可重复读和虚读。

3

TransactionDefinition.ISOLATION_READ_UNCOMMITTED

代表能够发生误读、不可重复读和虚读。

4

TransactionDefinition.ISOLATION_REPEATABLE_READ

代表可以阻止误读和不可重复读;能够发生虚读。

5

TransactionDefinition.ISOLATION_SERIALIZABLE

代表可以阻止误读、不可重复读和虚读。

下面是传播类型的可能值:

序号 传播 & 描述
1

TransactionDefinition.PROPAGATION_MANDATORY

支持当前事务;若是不存在当前事务,则抛出一个异常。

2

TransactionDefinition.PROPAGATION_NESTED

若是存在当前事务,则在一个嵌套的事务中执行。

3

TransactionDefinition.PROPAGATION_NEVER

不支持当前事务;若是存在当前事务,则抛出一个异常。

4

TransactionDefinition.PROPAGATION_NOT_SUPPORTED

不支持当前事务;而老是执行非事务性。

5

TransactionDefinition.PROPAGATION_REQUIRED

支持当前事务;若是不存在事务,则建立一个新的事务。

6

TransactionDefinition.PROPAGATION_REQUIRES_NEW

建立一个新事务,若是存在一个事务,则把当前事务挂起。

7

TransactionDefinition.PROPAGATION_SUPPORTS

支持当前事务;若是不存在,则执行非事务性。

8

TransactionDefinition.TIMEOUT_DEFAULT

使用默认超时的底层事务系统,或者若是不支持超时则没有。

TransactionStatus 接口为事务代码提供了一个简单的方法来控制事务的执行和查询事务状态。

public interface TransactionStatus extends SavepointManager {
   boolean isNewTransaction();
   boolean hasSavepoint();
   void setRollbackOnly();
   boolean isRollbackOnly();
   boolean isCompleted();
}
序号 方法 & 描述
1

boolean hasSavepoint()

该方法返回该事务内部是否有一个保存点,也就是说,基于一个保存点已经建立了嵌套事务。

2

boolean isCompleted()

该方法返回该事务是否完成,也就是说,它是否已经提交或回滚。

3

boolean isNewTransaction()

在当前事务时新的状况下,该方法返回 true。

4

boolean isRollbackOnly()

该方法返回该事务是否已标记为 rollback-only。

5

void setRollbackOnly()

该方法设置该事务为 rollback-only 标记。

Spring 编程式事务管理

极大地灵活性,可是它很难维护。

public class StudentJDBCTemplate implements StudentDAO {
   private DataSource dataSource;
   private JdbcTemplate jdbcTemplateObject;
   private PlatformTransactionManager transactionManager;

   public void create(String name, Integer age, Integer marks, Integer year){
      TransactionDefinition def = new DefaultTransactionDefinition();
      TransactionStatus status = transactionManager.getTransaction(def);
      try {
         String SQL1 = "insert into Student (name, age) values (?, ?)";
         jdbcTemplateObject.update( SQL1, name, age);
       
         String SQL2 = "select max(id) from Student";
         int sid = jdbcTemplateObject.queryForInt( SQL2 );
         String SQL3 = "insert into Marks(sid, marks, year) " + 
                       "values (?, ?, ?)";
         jdbcTemplateObject.update( SQL3, sid, marks, year);
         System.out.println("Created Name = " + name + ", Age = " + age);
         transactionManager.commit(status);
      } catch (DataAccessException e) {
         System.out.println("Error in creating record, rolling back");
         transactionManager.rollback(status);
         throw e;
      }
      return;
   }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd ">

   <!--配置数据源-->
   <bean id="dataSource" 
      class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
      <property name="url" value="jdbc:mysql://localhost:3306/TEST"/>
      <property name="username" value="root"/>
      <property name="password" value="password"/>
   </bean>

   <!--配置事务管理属性-->
   <bean id="transactionManager" 
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource"  ref="dataSource" />    
   </bean>

   <!--配置数据库操做对象,并实现依赖注入-->
   <bean id="studentJDBCTemplate"
      class="com.tutorialspoint.StudentJDBCTemplate">
      <property name="dataSource"  ref="dataSource" />
      <property name="transactionManager"  ref="transactionManager" />    
   </bean>

</beans>

Spring声明式事务管理

声明式事务管理方法容许你在配置的帮助下而不是源代码硬编程来管理事务。这意味着你能够将事务管理从事务代码中隔离出来。你能够只使用注释或基于配置的XML来管理事务。豆配置会指定事务型方法。下面是与声明式事务相关的步骤:

  • 咱们使用标签,它建立一个事务处理的建议,同时,咱们定义一个匹配全部方法的切入点,咱们但愿这些方法是事务型的而且会引用事务型的建议。

  • 若是在事务型配置中包含了一个方法的名称,那么建立的建议在调用方法以前就会在事务中开始进行。

  • 目标方法会在try / catch块中执行

  • 若是方法正常结束,AOP建议会成功的提交事务,不然它执行回滚操做。
<!-- Initialization for data source -->
   <bean id="dataSource" 
      class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
      <property name="url" value="jdbc:mysql://localhost:3306/TEST"/>
      <property name="username" value="root"/>
      <property name="password" value="cohondob"/>
   </bean>

   <tx:advice id="txAdvice"  transaction-manager="transactionManager">
      <tx:attributes>
      <tx:method name="create"/>
      </tx:attributes>
   </tx:advice>

   <aop:config>
      <aop:pointcut id="createOperation" 
      expression="execution(* com.tutorialspoint.StudentJDBCTemplate.create(..))"/>
      <aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation"/>
   </aop:config>

   <!-- Initialization for TransactionManager -->
   <bean id="transactionManager"
   class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource"  ref="dataSource" />    
   </bean>

   <!-- Definition for studentJDBCTemplate bean -->
   <bean id="studentJDBCTemplate"  
   class="com.tutorialspoint.StudentJDBCTemplate">
      <property name="dataSource"  ref="dataSource" />  
   </bean>
public void create(String name, Integer age, Integer marks, Integer year){
      try {
         String SQL1 = "insert into Student (name, age) values (?, ?)";
         jdbcTemplateObject.update( SQL1, name, age);
         // Get the latest student id to be used in Marks table
         String SQL2 = "select max(id) from Student";
         int sid = jdbcTemplateObject.queryForInt( SQL2 );
         String SQL3 = "insert into Marks(sid, marks, year) " + 
                       "values (?, ?, ?)";
         jdbcTemplateObject.update( SQL3, sid, marks, year);
         System.out.println("Created Name = " + name + ", Age = " + age);
         // to simulate the exception.
         throw new RuntimeException("simulate Error condition") ;
      } catch (DataAccessException e) {
         System.out.println("Error in creating record, rolling back");
         throw e;
      }
   }
相关文章
相关标签/搜索