MySQL筆記(十)MySQL事務 transaction

一、爲什麼要有事務?

用一個很經典的例子:

事務廣泛的運用於訂單系統、銀行系統等多種場景。如果有以下一個場景:
A用戶和B用戶是銀行的儲戶。現在A要給B轉賬500元。那麼需要做以下幾件事:

1. 檢查A的賬戶餘額>500元;
2. A賬戶扣除500元;
3. B賬戶增加500元;

正常的流程走下來,A賬戶扣了500,B賬戶加了500,皆大歡喜。那如果A賬戶扣了錢之後,系統出故障了呢?
A白白損失了500,而B也沒有收到本該屬於他的500。以上的案例中,隱藏着一個前提條件:
A扣錢和B加錢,要麼同時成功,要麼同時失敗。事務的需求就在於此。

事務作用:

一個事務中的所有操作作爲一個單元,要麼完全地執行,要麼完全地不執行。

事務是爲了確保數據的完整性和一致性,保證成批的 SQL 語句要麼全部執行,要麼全部不執行。

MySQL 事務注意點:
   1、在 MySQL 中只有使用了 Innodb 數據庫引擎的數據庫或表才支持事務。
   2、事務用來管理 insert,update,delete 語句,不能回退 CREATE 或 DROP 操作


二、事務的基本要素(ACID)

(1)A(atomicity) 原子性。一個事務的執行被視爲一個不可分割的最小單元。事務裏面的操作,要麼全部成功執行,要麼全部失敗回滾,不可以只執行其中的一部分。

(2)C(consistency) 一致性。一個事務的執行不應該破壞數據庫的完整性約束。如果上述例子中第2個操作執行後系統崩潰,
保證A和B的金錢總計是不會變的。

(3)I(isolation) 隔離性。通常來說,事務之間的行爲不應該互相影響。然而實際情況中,事務相互影響的程度受到隔離級別的影響。
(4)D(durability) 持久性。事務提交之後,需要將提交的事務持久化到磁盤。即使系統崩潰,提交的數據也不應該丟失。


三、事務的併發問題

1、髒讀:事務A讀取了事務B更新的數據,然後B回滾操作,那麼A讀取到的數據是髒數據

2、不可重複讀:事務 A 多次讀取同一數據,事務 B 在事務A多次讀取的過程中,對數據作了更新並提交,導致事務A多次讀取同一數據時,結果不一致。

3、幻讀:系統管理員A將數據庫中所有學生的成績從具體分數改爲ABCDE等級,但是系統管理員B就在這個時候插入了一條具體分數的記錄,當系統管理員A改結束後發現還有一條記錄沒有改過來,就好像發生了幻覺一樣,這就叫幻讀。

不可重複讀的和幻讀理解:

不可重複讀的和幻讀很容易混淆,不可重複讀側重於修改,幻讀側重於新增或刪除。解決不可重複讀的問題只需鎖住滿足條件的行,解決幻讀需要鎖表


四、事務控制語句

開啓一個事務;
BEGIN 或 START TRANSACTION;

COMMIT 會提交事務,並使已對數據庫進行的所有修改成爲永久性的;
COMMIT 也可以使用 COMMIT WORK ,不過二者是等價的。

回滾會結束用戶的事務,並撤銷正在進行的所有未提交的修改;
ROLLBACK 也可以使用 ROLLBACK WORK ,不過二者是等價的。

SAVEPOINT 允許在事務中創建一個保存點,一個事務中可以有多個SAVEPOINT;
SAVEPOINT identifier; 

刪除一個事務的保存點,當沒有指定的保存點時,執行該語句會拋出一個異常;
RELEASE SAVEPOINT identifier;

把事務回滾到標記點;
ROLLBACK TO identifier;

用來設置事務的隔離級別
SET TRANSACTION

MYSQL 事務處理主要有兩種方法:

1、用 BEGIN, ROLLBACK, COMMIT 來實現

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

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

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

五、查看修改MySQL的存儲引擎

看你的mysql現在已提供什麼存儲引擎:
show engines;
 
看你的mysql當前默認的存儲引擎:
show variables like '%storage_engine%';
 
你要看某個表用了什麼引擎(在顯示結果裏參數engine後面的就表示該表當前用的存儲引擎):
show create table tb_dept;
 
如何查看Mysql服務器上的版本
select version();

修改表引擎方法
alter table tb_dept engine=innodb;

mysql事物,rollback不起作用,怎麼回事?
這時候就要查看你數據庫、表的引擎是什麼

六、MySQL事務隔離級別

事務隔離級別

髒讀

不可重複讀

幻讀

讀未提交(read-uncommitted)

讀提交(read-committed)

可重複讀(repeatable-read)

串行化(serializable)

MySQL默認的事務隔離級別爲repeatable-read

所用的表和數據 MySQL筆記(二)基礎的增刪改查

事務隔離級別測試test:

注意;測試時每一個事物都需要開啓一個客戶端

事務隔離級別測試test:
注意;測試時每一個事物都需要開啓一個客戶端

(1)第一級別:讀未提交(read-uncommitted) 
1、所有事務都可以看到其他未提交事務的執行結果
2、本隔離級別很少用於實際應用,因爲它的性能也不比其他級別好多少
3、該級別引發的問題是——髒讀(Dirty Read):讀取到了未提交的數據

1、首先,修改隔離級別
set tx_isolation='read-uncommitted';
select @@tx_isolation;

2、客戶端A開啓事物1 
START TRANSACTION;
SELECT *FROM tb_dept;

3、客戶端B開啓事物2
在這事務中更新數據,且未提交
BEGIN;
UPDATE tb_dept SET loc='十堰2' WHERE deptno=7200;
SELECT * FROM tb_dept;

4、客戶端A查看數據
SELECT *FROM tb_dept;
重點:事物2能查看事物1未提交改變的髒數據,這就是髒讀

5、客戶端B回滾rollback
ROLLBACK;
SELECT * FROM tb_dept;

6、客戶端A事物1查詢
SELECT *FROM tb_dept;

(2)第二級別:讀提交(read-committed)
1、這是大多數數據庫系統的默認隔離級別(但不是MySQL默認的)
2、它滿足了隔離的簡單定義:一個事務只能看見已經提交事務所做的改變
3、這種隔離級別出現的問題是不可重複讀(Nonrepeatable Read):
不可重複讀意味着我們在同一個事務中執行完全相同的select語句時可能看到不一樣的結果。

導致這種情況的原因可能有:
(1)有一個交叉的事務有新的commit,導致了數據的改變;
(2)一個數據庫被多個實例操作時,同一事務的其他實例在該實例處理其間可能會有新的commit。

1、首先,修改隔離級別
SET tx_isolation='read-committed';
SELECT @@tx_isolation;

2、客戶端A開啓事物1 
START TRANSACTION;
SELECT *FROM tb_dept;

3、客戶端B開啓事物2
在這事務中更新數據,且未提交
BEGIN;
UPDATE tb_dept SET loc='十堰2' WHERE deptno=7200;
SELECT * FROM tb_dept;

4、客戶端A事物1查詢
SELECT *FROM tb_dept;
注意:此時查看的是未提交的數據,原來表數據

5、客戶端B提交事物commit;
commit後就不能rollback了 
COMMIT;

6、客戶端A事物1查看數據
SELECT *FROM tb_dept;
重點:此時查看的是事物2提交的數據,和第四步相同的select語句,結果卻不一樣

(3)第三級別:可重複讀(repeatable-read)     
1、這是MySQL的默認事務隔離級別
2、它確保同一事務的多個實例在併發讀取數據時,會看到同樣的數據行
3、此級別可能出現的問題——幻讀(Phantom Read):
當用戶讀取某一範圍的數據行時,另一個事務又在該範圍內插入了新行,當用戶再讀取該範圍的數據行時,會發現有新的“幻影” 行
4、InnoDB和Falcon存儲引擎通過多版本併發控制(MVCC,Multiversion Concurrency Control)機制解決了該問題

1、首先,修改隔離級別
SET tx_isolation='repeatable-read';
SELECT @@tx_isolation;

2、客戶端A開啓事物1 
START TRANSACTION;
SELECT *FROM tb_dept;

3、客戶端B開啓事物2
在這事務中更新數據,並且提交了
BEGIN;
UPDATE tb_dept SET loc='十堰2' WHERE deptno=7200;
SELECT * FROM tb_dept;
COMMIT;

4、客戶端A事物1查詢
SELECT *FROM tb_dept;
重點:這時候即使事務2已經提交了,但事物2還是看不到數據的變化。

只有事物1提交了,才能看到數據的變化
COMMIT;
SELECT *FROM tb_dept;

(4)第四級別:串行化(serializable)      
1、這是最高的隔離級別
2、它通過強制事務排序,使之不可能相互衝突,從而解決幻讀問題。簡言之,它是在每個讀的數據行上加上共享鎖。
3、在這個級別,可能導致大量的超時現象和鎖競爭

1、首先,修改隔離級別
SET tx_isolation='serializable';
SELECT @@tx_isolation;

2、客戶端A開啓事物1 
START TRANSACTION;

3、客戶端B開啓事物2
BEGIN;
UPDATE tb_dept SET loc='十堰2' WHERE deptno=7200;
重點:在事物1沒有commit之前,這個交叉事務是不能更改數據的

 

 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章