1、事務簡介
- 一個"最小的"不可再分的"工作單元"。
- 一個事務通常對應了一個完整的業務。如:銀行的轉賬功能,a轉賬給b,a扣錢,b加錢。
- 一個事務包含一條或多條DML語句(insert,update,delete)。
- 在一個事務中要么所有的語句都成功執行,要么都失敗,即所有的DML語句都成功執行才會修改硬盤數據。
在mysql命令行模式下,事務是自動提交的,每執行一條DML語句都會開啟一個事務,執行成功后立即執行commit操作。可以通過"show variables like '%commit%';" 查看事務的是否自動開啟。
2、事務的四個屬性
① 原子性:最小的工作單元,不可再分。事務中的所有操作必須全部成功或全部失敗,成功后寫入底層數據,失敗后回滾rollback到事務開啟的狀態。
② 一致性:事務在完成時,必須使所有的數據都保持一致狀態,保持數據庫的完整性。
③ 隔離性:並發事務之間存在隔離,互不干擾。
④ 持久性:事務完成之后,它對於系統的影響是永久性的。該修改即使出現致命的系統故障也將一直保持。
3、事務控制語句
- commit 事務提交
- rollback 事務回滾
- begin 開啟事務
- start transaction 開啟事務 同begin
- set transaction 設置事務隔離級別,只對當前會話有效
1)事務結束標志
事務提交或回滾,在mysql中默認開啟自動提交事務,即執行一條insert,update,,delect,會自動提交事務
2)關閉自動提交事務的方式1
手動開啟一個事務
begin; DML語句.. DML語句.. ... commit/rollback;
3)關閉自動提交事務的方式2 ,這種方式最對當前會話有效。更改后通過 "show variables like '%commit%';" 查看事務開啟狀態
set autocommit = off; # 關閉自動提交事務 set autocommit = on; # 開啟自動提交事務
4、事務四個隔離級別
- read uncommitted 讀未提交
- read committed 讀以提交
- repeatable read 可重復讀
- serializable 串行化
這四個隔離級別逐漸增高。
① read uncommitted:事務A未提交的數據,事務B也可以讀取到,這種隔離級別最低。這種事務會導致"dirty read(臟讀)"。因為事務A的數據還沒有提交,事務B就可以讀取到,那如果事務A在事務B讀取后回滾了呢,就導致了事務B讀取到的數據是"臟數據"。
② read committed:事務A未提交的數據,事務B讀取不到,事務A提交后的數據事務B才能讀取到。這個事務級別不會導致"dirty read",但會導致"不可重復讀"。假設事務A需要半天,在這期間有很多的其它事務都在修改數據,那么就導致了一個問題,事務A在開啟時讀到的數據與半天后讀到的數據差別很大,那么事務A需要在這半天內讀到的數據都是一樣的該怎么辦,比如每個月底網絡運營商系統出賬的時候,那肯定得在出賬期間讀到的數據都必須一樣才行。
③ repeatable read:事務A提交后的數據,事務B讀取不到,事務B讀取的數據依舊是事務B剛開始時的數據。MySQL的事務默認是這個級別。
④ serializable:事務A在執行的時候,事務B只能等待,就是說當多個事務需要執行時,只能排隊一個個的來,就是串行化的字面意思了。這種隔離級別最高,但會導致數據庫的吞吐量很低一般不用。
5、實例
1)需要用到的表

CREATE TABLE `bank` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(30) NOT NULL, `money` int(255) NOT NULL, PRIMARY KEY (`id`) )

INSERT INTO `bank` VALUES (0, 'zhangsan', 1000), (0, 'lisi', 2000), (0, 'wangwu', 500), (0, 'zhaoliu', 1300);
2)'lisi' 給 'zhangsan' 轉賬 500

mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update bank set money=money+500 where name='zhangsan'; Query OK, 1 row affected (0.01 sec) mysql> update bank set money=money-500 where name='lisi'; Query OK, 1 row affected (0.01 sec) mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> select * from bank; +----+----------+-------+ | id | name | money | +----+----------+-------+ | 1 | zhangsan | 1500 | | 2 | lisi | 1500 | | 3 | wangwu | 500 | | 4 | zhaoliu | 1300 | +----+----------+-------+ 4 rows in set (0.00 sec)