定義:數據庫事務是構成單一邏輯工作單元的操作集合。
一個典型的數據庫事務如下:
BEGIN TRANSACTION //事務開始
SQL1
SQL2
COMMIT/ROLLBACK //事務提交或回滾
可以理解為:將一組SQL放在一個批次中去執行
關於事務的定義有幾點需要解釋:
-
數據庫事務可以包含一個或多個數據庫操作,但這些操作構成一個邏輯上的整體。
-
構成邏輯整體的這些數據庫操作,要么全部執行成功,要么全部不執行。
-
構成事務的所有操作,要么全都對數據庫產生影響,要么全都不產生影響,即不管事務是否執行成功,數據庫總能保持一致性狀態。
-
2.事務的四個原則
事務的四個原則:ACID(原子性、一致性、隔離性、持久性)
參考博客
2.1 原子性(Atomicity)
原子性是指事務是一個不可分割的工作單位,事務中的操作,要么都發生,要么都不發生;要么都成功,要么都失敗。
針對同一個事務而言
舉例:銀行轉賬

這個過程包含兩個步驟:
A:800 - 200 = 600 轉出200
B:200 + 200 = 400 轉入200
原子性表示,這兩個步驟要么一起成功,要么一起失敗,不能只發生其中一個動作。
2.2 一致性(Consistency)
一致性是指事務前后的數據完整性要保持一致(最終一致性、過程一致性)。
針對一個事務操作前與操作后的狀態一致。
舉例:銀行轉賬

操作前A:800,B:200
操作后A:600,B:400
一致性表示事務完成后,符合邏輯運算(前后過程、最終的總錢數也都保持一致:1000)
2.3 持久性(Durability)
持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的(不可逆,被持久化到數據庫中),接下來即使數據庫發生故障也不應該對其產生任何影響。
表示事務結束后的數據不隨着外界原因導致數據丟失。
舉例:銀行轉賬
操作前A:800,B:200
操作后A:600,B:400
-
如果在操作前(即事務還沒有被提交)服務器宕機或者斷電,那么重啟數據庫以后,數據狀態應該為 A:800,B:200
-
如果在操作后(即事務已經被提交)服務器宕機或者斷電,那么重啟數據庫以后,數據狀態應該為 A:600,B:400
2.4 隔離性(Isolation)
事務的隔離性是指多個用戶並發訪問數據庫時,數據庫為每一個用戶開啟的事務,不能被其他事務的操作數據所干擾,多個並發事務之間要相互隔離。
針對多個用戶同時操作,主要是排除其他事務對本次事務的影響。
舉例:銀行轉賬

事務一:A向B轉賬200
事務二:C向B轉賬100
兩個事務同時進行,其中一個事務讀取到另外一個事務還沒有提交的數據,執行步驟如圖所示:

隔離性用於解決以上問題。
3.隔離所導致的一些問題
3.1 臟讀
指一個事務讀取了另外一個事務未提交的數據。
舉例:

3.2 不可重復讀
在一個事務內讀取表中的某一行數據,多次讀取結果不同(這不一定是錯誤,只是某些場合不對)。
舉例:頁面統計查詢值

生成報表的時候,B有人轉賬進來300(B事務已經提交)

3.3 虛讀(幻讀)
是指在一個事務內讀取到了別的事務插入的數據,導致前后讀取的不一樣,一般是行影響。
舉例:多了一行

4.事務流程
-- mysql是默認開啟事務自動提交的
SET autocommit=0 /* 關閉事務自動提交 */
SET autocommit=1 /* 開啟事務自動提交 */
-- 手動處理事務,要先關閉自動提交
SET autocommit=0
-- 標記一個事務的開始,從這個之后的sql都在同一個事務內
START TRANSACTION
-- 一組事務
INSERT xx
INSERT xx
-- 提交:成功-->持久化,就不能再回滾了
COMMIT
-- 回滾:失敗-->回滾(回到原來的樣子),未提交時,可以回滾
ROLLBACK
-- 事務結束,開啟自動提交
SET autocommit=1
-- 了解
SAVEPOINT 保存點名 -- 設置一個事務的保存點
ROLLBACK TO SAVEPOINT 保存點名 -- 回滾到保存點
RELEASE SAVEPOINT 保存點名 -- 撤銷保存點
4.1 轉賬業務舉例
舉例:轉賬業務
-- 事務案例:轉賬業務
-- 創建數據庫
CREATE DATABASE `bank` CHARACTER SET utf8 COLLATE utf8_general_ci
-- 使用數據庫
USE `bank`
-- 創建表
CREATE TABLE `account`(
`id` INT(4) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
-- 插入數據
INSERT INTO `account`(`name`,`money`) VALUES('A',10000.00),('B',20000.00)
-- 模擬轉賬:事務
SET autocommit=0; -- 關閉自動提交
START TRANSACTION -- 開始一個事務(一組事務)
-- 具體事務
UPDATE `account` SET `money`=`money`-500 WHERE `name`='A' -- A減500
UPDATE `account` SET `money`=`money`+500 WHERE `name`='B' -- B加500
COMMIT -- 成功提交事務,數據就被持久化了
ROLLBACK -- 失敗回滾事務
SET autocommit=1; -- 事務結束,開啟自動提交
