事務

事務是一組操作的集合,是一個不可分割的操作

事務會把所有的操作作為一個整體,一起向數據庫提交或者是撤銷操作請求,所以這組操作要麼同時成功要麼同時失效

事務應用

比如轉賬操作:

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';

代碼準備:

配置文件

微服務:事務管理 -_#spring boot

實體類

微服務:事務管理 -_#java_02

微服務:事務管理 -_回滾_03

Mapper

微服務:事務管理 -_回滾_04

微服務:事務管理 -_事務隔離級別_05

Service

微服務:事務管理 -_#spring boot_06

微服務:事務管理 -_數據庫_07

Controller

微服務:事務管理 -_回滾_08

Spring 編程式事務

Spring 手動操作事務 和 Mysql 操作事務類似,有 3 個重要操作步驟:

開啓事務

提交事務

回滾事務

微服務:事務管理 -_數據庫_09

微服務:事務管理 -_#spring boot_10

微服務:事務管理 -_回滾_11

數據庫插入成功

我們打開回滾來看看

微服務:事務管理 -_數據庫_12

微服務:事務管理 -_回滾_13

雖然 註冊成功了,但是數據庫並沒有新增數據

2.聲明式事務 @Transactional

聲明式事務實現只需在事務的方法上添加 @Transactional 註解就可以實現了

無需手動開啓事務和提交事務,進行方法時自動開啓事務,方法執行完會自動提交事務,如果中途發生了沒處理的異常會自動回滾事務

微服務:事務管理 -_事務隔離級別_14

微服務:事務管理 -_事務隔離級別_15

微服務:事務管理 -_#java_16

我們試一下異常會咋樣

微服務:事務管理 -_事務隔離級別_17

微服務:事務管理 -_#spring boot_18

微服務:事務管理 -_數據庫_19

@Transactional 作用

它可以用來修飾方法 和 類:

修飾方法時:只有修飾 public 方法時才能生效

修飾類時:對 @Transactional 修飾的類中所有的 public 方法都生效

需要注意的是我們前面説出現異常沒有處理時,就會回滾,但要是將異常給捕獲了的話,方法會被認為成功執行,依然會提交事務

我們試着捕獲一下:

微服務:事務管理 -_#spring boot_20

微服務:事務管理 -_事務隔離級別_21

如果我們要事務進行回滾有兩種方法:

1.重新拋出異常

微服務:事務管理 -_數據庫_22

2.手動回滾事務

微服務:事務管理 -_事務隔離級別_23

使用 

TransactionAspectSupport.currentTransactionStatus()

來獲取事務,並且設置回滾

@Transactional 

@Transactional 中常見的三個屬性:

1.rollbackFor

異常回滾屬性,指定能夠出發事務回滾的異常類型

@Transactional  默認只在遇到運行時異常和Error時才會回滾,非運行時異常不會滾,既 Exception 的子類中,除了 RuntimeException 及其子類

微服務:事務管理 -_事務隔離級別_24

微服務:事務管理 -_事務隔離級別_25

微服務:事務管理 -_數據庫_26

出現了異常,但是並沒有出發回滾

我們需要所有的異常都進行回滾,通常需要配置 @Transactional,rollbackFor 指定出現何種異常類型時事務進行回滾

微服務:事務管理 -_數據庫_27

微服務:事務管理 -_數據庫_28

現在在出發這種類型的異常就進行了回滾了

2.Isolation

事務隔離級別

讀未提交

讀提交

可重複讀

串行化

微服務:事務管理 -_數據庫_29

這在 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 一致

部分執行成功時

會導致整個事務全部回滾

可實現局部回滾,不影響上一個方法的執行結果