事務
事務是一組操作的集合,是一個不可分割的操作
事務會把所有的操作作為一個整體,一起向數據庫提交或者是撤銷操作請求,所以這組操作要麼同時成功要麼同時失效
事務應用
比如轉賬操作:
1.賬户 A 給 賬户 B 轉了 100元
2.賬户 B 的賬户 +100元
這是如果沒有事務的話,就可能會出現第一步實現了,但是第二步沒有實現,導致賬户 A 的錢減少了,但是賬户 B 卻未到賬的問題。
雖然事務沒有辦法去解決第二步為啥沒有實現的這個問題,但是可是使得 B 要是沒有收到錢的話,A 的賬户就不會減少
要麼一起成功,要麼一起失敗
事務的操作
事務的操作主要分為三步:
1.開啓事務: start transaction/begin (一組操作前開啓事務)
2.提交事務:commit
3. 回滾事務: roolback
Spring 中事務的實現
Spring 中的事務操作分為兩類:
1.編程式事務
需求:用户註冊時在日誌表中插入一條操作記錄
數據準備:
-- 創建數據庫
DROP DATABASE IF EXISTS trans_test;
CREATE DATABASE trans_test DEFAULT CHARACTER SET utf8mb4;
-- 切換到目標數據庫
USE trans_test;
-- 用户表
DROP TABLE IF EXISTS user_info;
CREATE TABLE user_info (
`id` INT NOT NULL AUTO_INCREMENT,
`user_name` VARCHAR (128) NOT NULL,
`password` VARCHAR (128) NOT NULL,
`create_time` DATETIME DEFAULT now(),
`update_time` DATETIME DEFAULT now() ON UPDATE now(),
PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARACTER SET = utf8mb4 COMMENT = '用户表';
-- 操作日誌表
DROP TABLE IF EXISTS log_info;
CREATE TABLE log_info (
`id` INT PRIMARY KEY auto_increment,
`user_name` VARCHAR ( 128 ) NOT NULL,
`op` VARCHAR ( 256 ) NOT NULL,
`create_time` DATETIME DEFAULT now(),
`update_time` DATETIME DEFAULT now() ON UPDATE now()
) DEFAULT charset 'utf8mb4';
代碼準備:
配置文件
實體類
Mapper
Service
Controller
Spring 編程式事務
Spring 手動操作事務 和 Mysql 操作事務類似,有 3 個重要操作步驟:
開啓事務
提交事務
回滾事務
數據庫插入成功
我們打開回滾來看看
雖然 註冊成功了,但是數據庫並沒有新增數據
2.聲明式事務 @Transactional
聲明式事務實現只需在事務的方法上添加 @Transactional 註解就可以實現了
無需手動開啓事務和提交事務,進行方法時自動開啓事務,方法執行完會自動提交事務,如果中途發生了沒處理的異常會自動回滾事務
我們試一下異常會咋樣
@Transactional 作用
它可以用來修飾方法 和 類:
修飾方法時:只有修飾 public 方法時才能生效
修飾類時:對 @Transactional 修飾的類中所有的 public 方法都生效
需要注意的是我們前面説出現異常沒有處理時,就會回滾,但要是將異常給捕獲了的話,方法會被認為成功執行,依然會提交事務
我們試着捕獲一下:
如果我們要事務進行回滾有兩種方法:
1.重新拋出異常
2.手動回滾事務
使用
TransactionAspectSupport.currentTransactionStatus()
來獲取事務,並且設置回滾
@Transactional
@Transactional 中常見的三個屬性:
1.rollbackFor
異常回滾屬性,指定能夠出發事務回滾的異常類型
@Transactional 默認只在遇到運行時異常和Error時才會回滾,非運行時異常不會滾,既 Exception 的子類中,除了 RuntimeException 及其子類
出現了異常,但是並沒有出發回滾
我們需要所有的異常都進行回滾,通常需要配置 @Transactional,rollbackFor 指定出現何種異常類型時事務進行回滾
現在在出發這種類型的異常就進行了回滾了
2.Isolation
事務隔離級別
讀未提交
讀提交
可重複讀
串行化
這在 MySQL 那裏已經做過詳細的介紹
Spring 事務隔離級別
|
序號
|
隔離級別常量
|
説明
|
對應 SQL 標準隔離級別
|
|
1
|
Isolation.DEFAULT
|
以連接的數據庫的事務隔離級別為主
|
-
|
|
2
|
Isolation.READ_UNCOMMITTED
|
讀未提交
|
READ UNCOMMITTED
|
|
3
|
Isolation.READ_COMMITTED
|
讀已提交
|
READ COMMITTED
|
|
4
|
Isolation.REPEATABLE_READ
|
可重複讀
|
REPEATABLE READ
|
|
5
|
Isolation.SERIALIZABLE
|
串行化
|
SERIALIZABLE
|
Spring 中事務隔離級別可以通過 @Transactional 中的 isolation 屬性進行設置
3.propagation
事務的傳播機制就是:多個事務方法存在調用關係中,事務是如何在這些方法間進行傳播的
比如有兩個方法 A 和 B 都被 @Transactional 修飾,A 方法調用了 B 方法
A 方法運行時開啓了事務,調用 B方法 的時候,B 本身也有事務,這個時候是加入 方法A 的事務 還是創建一個新的事務,這就涉及到了 事務的傳播機制
事務隔離級別是解決多個事務同時調用一個數據庫的問題
事務傳播機制解決的是一個事務在多個節點中傳遞的問題
事務的傳播機制有哪些
Spring 中事務傳播機制可以通過 @Transactional 中的 propagation 屬性來制定傳播行為
Spring 中事務傳播機制有 7 種:
|
序號
|
事務傳播行為
|
説明
|
|
1
|
Propagation.REQUIRED
|
默認傳播級別。若當前存在事務,加入該事務;若不存在,創建新事務。
|
|
2
|
Propagation.SUPPORTS
|
若當前存在事務,加入該事務;若不存在,以非事務方式運行。
|
|
3
|
Propagation.MANDATORY
|
強制要求當前存在事務,若不存在則拋出異常。
|
|
4
|
Propagation.REQUIRES_NEW
|
無論當前是否存在事務,均創建新事務;若當前有事務,將其掛起。內部事務與外部事務相互獨立。
|
|
5
|
Propagation.NOT_SUPPORTED
|
以非事務方式運行;若當前存在事務,將其掛起。
|
|
6
|
Propagation.NEVER
|
以非事務方式運行;若當前存在事務,拋出異常。
|
|
7
|
Propagation.NESTED
|
若當前存在事務,創建嵌套事務運行;若不存在,等價於 Propagation.REQUIRED。
|
|
對比項
|
Propagation.REQUIRED
|
Propagation.NESTED
|
|
執行成功時
|
結果與 NESTED 一致
|
結果與 REQUIRED 一致
|
|
部分執行成功時
|
會導致整個事務全部回滾
|
可實現局部回滾,不影響上一個方法的執行結果
|