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;
      }
   }
相關文章
相關標籤/搜索