在此之前,我們已經了解了 Spring 相關的基礎知識,今天將為給位帶來,有關 Spring 事務代理的相關知識。關注我的公眾號「Java面典」,每天 10:24 和你一起了解更多 Java 相關知識點。
事務管理方式
在 Spring 項目中,我們可以用通過四種方式實現事務管理,分別是 編程式事務管理、基於 TransactionProxyFactoryBean的聲明式事務管理、基於 @Transactional 的聲明式事務管理 和 基於Aspectj AOP配置事務。其實現方式如下:
編程式事務管理
// JDBC 事務管理
Connection connection = DriverManager.getConnection("connUrl", "username", "password");
//關閉自動提交,此句代碼會自動開啟事務。默認為true,自動提交。
connection.setAutoCommit(false);
String sql1 = "insert into user(name) values (?)";
PreparedStatement preparedStatement1 = connection.prepareStatement(sql1);
preparedStatement1.setString(1,"Java面典");
preparedStatement1.executeUpdate();
String sql2 = "update user set name=? where id=?";
PreparedStatement preparedStatement2 = connection.prepareStatement(sql2);
preparedStatement2.setString(1, "Java面典 new");
preparedStatement2.setInt(2, 10);
preparedStatement2.executeUpdate();
try{
//提交事務
connection.commit();
}catch (SQLException e){
//失敗就回滾
connection.rollback();
} finally {
preparedStatement1.close();
preparedStatement2.close();
connection.close();
}
基於 TransactionProxyFactoryBean的聲明式事務管理
<?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: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.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
基於 @Transactional 的聲明式事務管理
@Service
public class UserServiceImpl implements IUserService {
@Transactional(transactionManager = "transactionManager", rollbackFor = Exception.class)
@Override
public void add(User user) {
// todo
}
}
基於Aspectj AOP配置事務
<!-- 事務管理器 -->
<bean id="tracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:advice id="txAdvice" transaction-manager="myTracnsactionManager">
<tx:attributes>
<!-- 為連接點指定事務屬性 -->
<tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED"/>
<tx:method name="stockChange" isolation="DEFAULT" propagation="REQUIRED" rollback-for="StockException"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 切入點配置 -->
<aop:pointcut expression="execution(* *..service.*.*(..))" id="point"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
</aop:config>
事務傳播機制
Spring 的事務傳播分為以下幾個機制:
-
REQUIRED:如果有事務則加入事務,如果沒有事務,則創建一個新的(默認值);
-
NOT_SUPPORTED:Spring 不為當前方法開啟事務,相當於沒有事務;
-
REQUIRES_NEW:不管是否存在事務,都創建一個新的事務,原來的方法掛起,新的方法執行完畢后,繼續執行老的事務;
-
MANDATORY:必須在一個已有的事務中執行,否則報錯;
-
NEVER:必須在一個沒有的事務中執行,否則報錯;
-
SUPPORTS:如果其他 bean 調用這個方法時,其他 bean 聲明了事務,則就用這個事務,如果沒有聲明事務,那就不用事務;
SUPPORTS類型的事務傳播機制,是否使用事務取決於調用方法是否有事務,如果有則直接用,如果沒有則不使用事務。
-
NESTED:如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行與 REQUIRED 類似的操作;
注意事項
在 A 方法內,調用 B 方法時,存在以下規則:
- REQUIRED
當兩個方法的傳播機制都是 REQUIRED 時,如果一旦發生回滾,兩個方法都會回滾; - REQUIRES_NEW
當 A 方法傳播機制為 REQUIRES_NEW ,會開啟一個新的事務,並單獨提交方法,所以 B 方法的回滾並不影響 A 方法事務提交; - NESTED
當 A 方法為 REQUIRED,B 方法為 NESTED 時,A 方法開啟一個嵌套事務;
當 A 方法回滾時,B 方法也會回滾;反之,如果 B 方法回滾,則並不影響 A 方法的提交。
事務隔離級別
TransactionDefinition 接口中定義了五個表示隔離級別的常量:
-
ISOLATION_DEFAULT:使用后端數據庫默認的隔離界別,MySQL默認采用的REPEATABLE_READ 隔離級別,Oracle 默認采用的 READ_COMMITTED 隔離級別;
-
ISOLATION_READ_UNCOMMITTED:最低的隔離級別,允許讀取,允許讀取尚未提交的的數據變更,可能會導致臟讀、幻讀或不可重復讀;
-
ISOLATION_READ_COMMITTED:允許讀取並發事務已經提交的數據,可以阻止臟讀,但是幻讀或不可重復讀仍有可能發生;
-
ISOLATION_REPEATABLE_READ:對同一字段的多次讀取結果都是一致的,除非數據是被本身事務自己所修改,可以阻止臟讀和不可重復讀,但幻讀仍有可能發生;
-
ISOLATION_SERIALIZABLE:最高的隔離級別,完全服從 ACID 的隔離級別。所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就說,該級別可以阻止臟讀、不可重復讀以及幻讀。但是這將嚴重影響程序的性能。通常情況下也不會用到該級別。