Mysql事務
1、概述
事務可以保證多個操作原子性,要麼全成功,要麼全失敗。對於數據庫來說事務保證批量的DML要麼全成功,要麼全失敗。事務具有四個特徵ACID
-
- 原子性(Atomicity)
- 整個事務中的所有操作,必須作爲一個單元全部完成(或全部取消)。
- 一致性(Consistency)
- 在事務開始之前與結束之後,數據庫都保持一致狀態。
- 隔離性(Isolation)
- 一個事務不會影響其他事務的運行。
- 持久性(Durability)
- 在事務完成以後,該事務對數據庫所作的更改將持久地保存在數據庫之中,並不會被回滾。
- 原子性(Atomicity)
事務中存在一些概念:
- 事務(Transaction):一批操作(一組DML)
- 開啓事務(Start Transaction)
- 回滾事務(rollback)
- 提交事務(commit)
- SET AUTOCOMMIT:禁用或啓用事務的自動提交模式
當執行DML語句是其實就是開啓一個事務
關於事務的回滾需要注意:只能回滾insert、delete和update語句,不能回滾select(回滾select沒有任何意義),對於create、drop、alter這些無法回滾.
事務只對DML有效果。
注意:rollback,或者commit後事務就結束了。
16.2、事務的提交與回滾演示
創建表
create table user( id int (11) primary key not null auto_increment , password varchar(30) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
|
- 查詢表中數據
- 開啓事務START TRANSACTION;
- 插入數據 insert into user (username,password) values ('zhangsan','123')
- 查看數據 一條記錄已經插入到表中
- 修改數據 表中數據已經被修改
- 查看數據 之前所做的操作已經“生效”
- 回滾事務 事務進行回滾,撤銷之前的操作
- 查看數據 回覆操作之前的狀態
3、自動提交模式
- 自動提交模式用於決定新事務如何及何時啓動。
- 啓用自動提交模式:
- 如果自動提交模式被啓用,則單條DML語句將缺省地開始一個新的事務。
- 如果該語句執行成功,事務將自動提交,並永久地保存該語句的執行結果。
- 如果語句執行失敗,事務將自動回滾,並取消該語句的結果。
- 在自動提交模式下,仍可使用START TRANSACTION語句來顯式地啓動事務。這時,一個事務仍可包含多條語句,直到這些語句被統一提交或回滾。
- 禁用自動提交模式:
- 如果禁用自動提交,事務可以跨越多條語句。
- 在這種情況下,事務可以用COMMIT和ROLLBACK語句來顯式地提交或回滾。
- 自動提交模式可以通過服務器變量AUTOCOMMIT來控制。
- 例如:
mysql> SET AUTOCOMMIT = OFF;
mysql> SET AUTOCOMMIT = ON;
或
mysql> SET SESSION AUTOCOMMIT = OFF;
mysql> SET SESSION AUTOCOMMIT = ON;
show variables like '%auto%'; -- 查看變量狀態
4、事務的隔離級別
4.1、隔離級別
- 事務的隔離級別決定了事務之間可見的級別。
- 當多個客戶端併發地訪問同一個表時,可能出現下面的一致性問題:
- 髒讀取(Dirty Read) 一個事務開始讀取了某行數據,但是另外一個事務已經更新了此數據但沒有能夠及時提交,這就出現了髒讀取。
- 不可重複讀(Non-repeatable Read) 在同一個事務中,同一個讀操作對同一個數據的前後兩次讀取產生了不同的結果,這就是不可重複讀。
- 幻像讀(Phantom Read) 幻像讀是指在同一個事務中以前沒有的行,由於其他事務的提交而出現的新行。
4.2、四個隔離級別
- InnoDB 實現了四個隔離級別,用以控制事務所做的修改,並將修改通告至其它併發的事務:
- 讀未提交(READ UMCOMMITTED) 允許一個事務可以看到其他事務未提交的修改。
- 讀已提交(READ COMMITTED) 允許一個事務只能看到其他事務已經提交的修改,未提交的修改是不可見的。
- 可重複讀(REPEATABLE READ) 確保如果在一個事務中執行兩次相同的SELECT語句,都能得到相同的結果,不管其他事務是否提交這些修改。 (銀行總賬)該隔離級別爲InnoDB的缺省設置。
- 串行化(SERIALIZABLE) 【序列化】將一個事務與其他事務完全地隔離。 (不常用)
例:A可以開啓事物,B也可以開啓事物
A在事物中執行DML語句時,未提交
B不以執行DML,DQL語句
4.3、隔離級別與一致性問題的關係
4.4、設置服務器缺省隔離級別
通過修改配置文件設置
- 可以在my.ini文件中使用transaction-isolation選項來設置服務器的缺省事務隔離級別。
- 該選項值可以是:
- READ-UNCOMMITTED
- READ-COMMITTED
- REPEATABLE-READ
- SERIALIZABLE
- 例如:
[mysqld]
transaction-isolation = READ-COMMITTED
通過命令動態設置隔離級別
- 隔離級別也可以在運行的服務器中動態設置,應使用SET TRANSACTION ISOLATION LEVEL語句。
- 其語法模式爲:
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL <isolation-level>
其中的<isolation-level>可以是:
-
- READ UNCOMMITTED
- READ COMMITTED
- REPEATABLE READ
- SERIALIZABLE
- 例如:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
4.5、隔離級別的作用範圍
- 事務隔離級別的作用範圍分爲兩種:
- 全局級:對所有的會話有效
- 會話級:只對當前的會話有效
- 例如,設置會話級隔離級別爲READ COMMITTED :
mysql> SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
或:
mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
- 設置全局級隔離級別爲READ COMMITTED :
mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
4.6、查看隔離級別
- 服務器變量tx_isolation(包括會話級和全局級兩個變量)中保存着當前的會話隔離級別。
- 爲了查看當前隔離級別,可訪問tx_isolation變量:
- 查看會話級的當前隔離級別:
mysql> SELECT @@tx_isolation;
或:
mysql> SELECT @@session.tx_isolation;
- 查看全局級的當前隔離級別:
mysql> SELECT @@global.tx_isolation;
4.7、併發事務與隔離級別示例
read uncommitted(未提交讀) --髒讀(Drity Read):
會話一 |
會話二 |
mysql> prompt s1> |
mysql> use bjpowernode |
s1>use bjpowernode |
mysql> prompt s2> |
s1>create table tx ( id int(11), num int (10) ); |
|
s1>set global transaction isolation level read uncommitted; |
|
s1>start transaction; |
|
|
s2>start transaction; |
s1>insert into tx values (1,10); |
|
|
s2>select * from tx; |
s1>rollback; |
|
|
s2>select * from tx; |
read committed(已提交讀)
會話一 |
會話二 |
s1> set global transaction isolation level read committed; |
|
s1>start transaction; |
|
|
s2>start transaction; |
s1>insert into tx values (1,10); |
|
s1>select * from tx; |
|
|
s2>select * from tx; |
s1>commit; |
|
|
s2>select * from tx; |
repeatable read(可重複讀)
會話一 |
會話二 |
s1> set global transaction isolation level repeatable read; |
|
s1>start transaction; |
s2>start transaction; |
s1>select * from tx; |
|
s1>insert into tx values (1,10); |
|
|
s2>select * from tx; |
s1>commit; |
|
|
s2>select * from tx; |