1. 程式人生 > 資料庫 >Spring管理資料庫事務

Spring管理資料庫事務

一、事務的一些基本概念
事務的屬性(ACID):

  • 原子性
  • 一致性
  • 隔離性
  • 永續性
    白話“事務”

事務有三個狀態(或者說是過程):開始、提交、回滾。
事務的隔離級別

隔離級別
描述
舉例
DEFAULT
底層資料庫儲存的預設隔離級別

READ_UNCOMMITTED
最低的隔離級別,可以說它並不是事務,因為它允許其他事務來讀取未來提交的資料
上邊的例子中,就算李四沒有收這10元,其他人也能讀取到李四多了10元。
READ_COMMITTED
大多數資料庫的預設級別,它確保其他事務可以讀取其他事務已經提交的資料
只有當李四對這10元進行操作(接收或者退回)時,別人才能看到這兩個的餘額變化。
REPEATABLE_READ

比上一個更為嚴格,它確保在選擇了資料後,如果其他事務對這個資料進行了更改,就可以選擇新的資料。
上邊的是在轉賬過程中,就算別人給張三又轉了10元,在這個事務提交前,張三一直認為自己只有100元。但是這個型別中,張三在轉賬過程中,可以查到自己有110元
SERIALIZABLE
可序列化,是最嚴格最可靠的隔離級別,讓所有事務一個接著一個地執行
系統讓每個人轉賬事務一個一個地執行,就不會有任何錯誤了(當然,這裡的事務不單單指轉賬這一個事務)
事務的傳播型別

也就是當前事務開始的機制和時間,相當於這麼多的人之間的微信轉賬應該怎麼進行
傳播型別
描述
PROPAGATION_REQUIRED
如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,加入到這個事務中;

PROPAGATION_SUPPORTS
支援當前事務,如果當前沒有事務,就以非事務方式執行;
PROPAGATION_MANDATORY
使用當前的事務,如果當前沒有事務,就丟擲異常;
PROPAGATION_REQUIRES_NEW
新建事務,如果當前存在事務,把當前事務掛起;
PROPAGATION_NOT_SUPPORTED
以非事務方式執行操作,如果當前存在事務,就把當前事務掛起;
PROPAGATION_NEVER
以非事務方式執行,如果當前存在事務,則丟擲異常;
PEOPAGATION_NESTED
如果當前存在事務,則在潛逃事務內執行。如果當前沒有事務,則執行PROPAGATION_REQUIRED列斯的操作;

二、Spring中解決事務問題
在Spring中解決事務問題有兩種:宣告式事務和程式設計式事務(不建議使用)
Spring中支援事務的最底層介面是PlatformTransactionManager,而我們使用的只能它的子類
public interface PlatformTransactionManager {
//獲取事務狀態
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
//提交
void commit(TransactionStatus var1) throws TransactionException;
//回滾
void rollback(TransactionStatus var1) throws TransactionException;
}
這個介面中主要用了TransactionDefinition和TransactionStatus兩個類。有興趣的可以看一下。下邊這是它的子類圖,我們這裡使用的是DataSourceTransactionManager作為事務管理類,不管使用何種方式,PlatformTransactionManager這個介面的子類一定要有。

  1. 宣告式事務
  • 使用註解
    配置檔案如下:

tx:annotation-driven/

<context:component-scan base-package=“cn.lyn4ever.service”/>
然後在類或方法上加上這個@Transactional註解就可以
@Transactional
public void insertOne(){
Store store =new Store();
store.setTitle(“華為P30”);
storeMapper.insertOne(store);

int j = 10/0;//指定報錯,讓事務回滾

}

  • 使用AOP配置
    使用aop的話,我們只需要進行配置,可以對我們寫的業務程式碼無任何侵入。如果對AOP知識不是很瞭解,可以參考我之前的AOP系列教程Spring學習筆記,AOP的配置也有多種,這裡就直接使用aop名稱空間了

<tx:advice id=“txAdvice”>
tx:attributes

<tx:method name=“insert*” rollback-for=“java.lang.Exception”/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

aop:config
<aop:pointcut id=“serviceTrans” expression=“execution(* cn.lyn4ever.serviceaop..(…))”/>
<aop:advisor advice-ref=“txAdvice” pointcut-ref=“serviceTrans”/>
</aop:config>

<context:component-scan base-package=“cn.lyn4ever.serviceaop”/>

  • 以上兩種方式的對比:
    • 使用註解能更加細粒度地進行控制,因為並不是所有service方法都需要事務。而使用AOP使用的面向切面程式設計,所以可以大批量的進行控制,而一般都是在service層進入切入的。
    • 使用註解的話,配置簡單,AOP的配置稍微複雜點兒。
    • 如果是新專案的話,建議從一開始就使用註解式開發。如果是更改之前沒有用過事務(一般成熟的程式設計師不會這麼幹)的專案,或者無法修改原始碼的情況下,建設使用AOP。
    • 個人經驗,建議使用註解開發,能靈活的配置每一個方法及類。使用AOP的話,有時候除錯起來不太方便,如果你的除錯內容跨越了一個service方法,會進入aop通知方法,很麻煩。
  1. 程式設計式事務

顧名思義,就是將事務的操作直接寫在業務程式碼中,這樣做最簡單,但是最不建議。有兩種方式,一種就是將PlatformTransactionManager的例項注入到bean中,使用它。另一種就是使用Spring為我們提供的TransactionTemplate。這裡直接使用第二種,這時,我們只需要使用Spring注入注入transactionManager和這兩個類,但是為了不和之前的配置混淆,我直接new這兩個物件了,也就是說,使用程式設計式事務,只需要這兩個物件就夠了,不需要其他任何有關事務的配置,只需要一個數據源
@Autowired
private DataSource dataSource;

@Test
public void fun() {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
//設定資料來源,這個資料來源的bean是由Spring提供的
transactionManager.setDataSource(dataSource);
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(txStatus -> {
Store store = new Store();
store.setTitle(“小米11”);
storeMapper.insertOne(store);
//製造錯誤,讓事務回滾
int i = 10 / 0;
return null;
});
}