1. 程式人生 > 實用技巧 >MySQL 之 事務

MySQL 之 事務

1、事務概述

​ MySQL 事務主要用於處理操作量大,複雜度高的資料。比如說,在員工管理系統中,刪除一個員工,既需要刪除員工的基本資料,也要刪除和該員工相關的資訊,如信箱,文章等等,這樣,這些資料庫操作語句就構成一個事務。

  • 在 MySQL 中只有使用了 Innodb 資料庫引擎的資料庫或表才支援事務。
  • 事務處理可以用來維護資料庫的完整性,保證成批的 SQL 語句要麼全部執行,要麼全部不執行。
  • 事務用來管理 insert,update,delete 語句

2、事務的ACID特性

	一般來說,事務是必須滿足4個條件(ACID)::原子性(**A**tomicity,或稱不可分割性)、一致性(**C**onsistency)、隔離性(**I**solation,又稱獨立性)、永續性(**D**urability)。 
  • 原子性:一個事務(transaction)中的所有操作,要麼全部完成,要麼全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
  • 一致性:在事務開始之前和事務結束以後,資料庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預設規則,這包含資料的精確度、串聯性以及後續資料庫可以自發性地完成預定的工作。
  • 隔離性:資料庫允許多個併發事務同時對其資料進行讀寫和修改的能力,隔離性可以防止多個事務併發執行時由於交叉執行而導致資料的不一致。事務隔離分為不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重複讀(repeatable read)和序列化(Serializable)。
  • 永續性:事務處理結束後,對資料的修改就是永久的,即便系統故障也不會丟失。

在 MySQL 命令列的預設設定下,事務都是自動提交的,即執行 SQL 語句後就會馬上執行 COMMIT 操作。因此要顯式地開啟一個事務務須使用命令 BEGIN 或 START TRANSACTION,或者執行命令 SET AUTOCOMMIT=0,用來禁止使用當前會話的自動提交。

3、事務的隔離級別

髒資料:是事務回滾的結果,讀取到另一個事務未提交的資料
不可重複讀 :多次讀取資料因修改不一致
        側重修改,鎖資料解決
幻讀:修改資料因插入操作個別未成功
        側重新增/刪除 ,鎖表解決

(1)、Read uncommitted(讀未提交)

​ 如果一個事務已經開始寫資料,則另外一個事務不允許同時進行寫操作,但允許其他事務讀此行資料,該隔離級別可以通過“排他寫鎖”,但是不排斥讀執行緒實現。這樣就避免了更新丟失,卻可能出現髒讀,也就是說事務B讀取到了事務A未提交的資料。

​ 特點:解決了更新丟失,但還是可能會出現髒讀

(2)、Read committed(讀提交)

​ 如果是一個讀事務(執行緒),則允許其他事務讀寫,如果是寫事務將會禁止其他事務訪問該行資料,該隔離級別避免了髒讀,但是可能出現不可重複讀。事務A事先讀取了資料,事務B緊接著更新了資料,並提交了事務,而事務A再次讀取該資料時,資料已經發生了改變。

​ 特點:解決了更新丟失和髒讀問題

(3)、Repeatable read(可重複讀取)

	可重複讀取是指在一個事務內,多次讀同一個資料,在這個事務還沒結束時,其他事務不能訪問該資料(包括了讀寫),這樣就可以在同一個事務內兩次讀到的資料是一樣的,因此稱為是可重複讀隔離級別,讀取資料的事務將會禁止寫事務(但允許讀事務),寫事務則禁止任何其他事務(包括了讀寫),這樣避免了不可重複讀和髒讀,但是有時可能會出現幻讀。(讀取資料的事務)可以通過“共享讀鏡”和“排他寫鎖”實現。

​ 特點:解決了更新丟失、髒讀、不可重複讀、但是還會出現幻讀

(4)、Serializable(可序化)

​ 提供嚴格的事務隔離,它要求事務序列化執行,事務只能一個接著一個地執行,但不能併發執行,如果僅僅通過“行級鎖”是無法實現序列化的,必須通過其他機制保證新插入的資料不會被執行查詢操作的事務訪問到。序列化是最高的事務隔離級別,同時代價也是最高的,效能很低,一般很少使用,在該級別下,事務順序執行,不僅可以避免髒讀、不可重複讀,還避免了幻讀。

​ 特點:解決了更新丟失、髒讀、不可重複讀、幻讀(虛讀)

​ 以上四種隔離級別最高的是Serializable級別,最低的是Read uncommitted級別,當然級別越高,執行效率就越低,像Serializeble這樣的級別,就是以鎖表的方式使得其他執行緒只能在鎖外等待,所以平時選用何種隔離級別應該根據實際情況來,在MYSQL資料庫中預設的隔離級別是Repeatable read(可重複讀)。

4、MySQL中設定事務的隔離級別

# 設定語法:
set [glogal | session] transaction isolation level 隔離級別名稱;
set tx_isolation = '隔離級別名稱';
# 例子
set session transaction isolation level read committed;
# 檢視當前事務的隔離級別
select @@tx_isolation;

記住:設定資料庫的隔離級別一定要是在開啟事務之前:

隔離級別的設定只對當前連線有效,對於使用MYSQL命令視窗而言,一個視窗就相當於一個連線,當前視窗設定的隔離級別只對當前視窗中的事務有效。

5、事務控制語句

# 開啟事務
BEGIN 或 START TRANSACTION 顯式地開啟一個事務;
# 提交事務
COMMIT 也可以使用 COMMIT WORK,不過二者是等價的。COMMIT 會提交事務,並使已對資料庫進行的所有修改成為永久性的;
# 事務回滾
ROLLBACK 也可以使用 ROLLBACK WORK,不過二者是等價的。回滾會結束使用者的事務,並撤銷正在進行的所有未提交的修改;
# 建立儲存點
SAVEPOINT identifier,SAVEPOINT 允許在事務中建立一個儲存點,一個事務中可以有多個 SAVEPOINT;
# 刪除儲存點
RELEASE SAVEPOINT identifier 刪除一個事務的儲存點,當沒有指定的儲存點時,執行該語句會丟擲一個異常;
# 將事務回滾到儲存點
ROLLBACK TO identifier 把事務回滾到標記點;
# 設定事務的隔離級別
SET TRANSACTION 用來設定事務的隔離級別。InnoDB 儲存引擎提供事務的隔離級別有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE。

6、MySQL事務處理的兩種主要方式

(1)、用 BEGIN, ROLLBACK, COMMIT來實現

BEGIN;     # 開始一個事務
ROLLBACK;  # 事務回滾
COMMIT;    # 事務確認

(2)、直接用 SET 來改變 MySQL 的自動提交模式

SET AUTOCOMMIT=0    # 禁止自動提交
SET AUTOCOMMIT=1    # 開啟自動提交