本篇內容是關於SQL事物知識,主要包括事物的概念,ACID,幻讀,不可重複度,髒度等內容;mysql
學習本篇的基礎是知識追尋者發過的SQL系列文章(公衆號讀者直接在專欄裏面找便可)sql
本套教程數據庫
公衆號:知識追尋者json
知識追尋者(Inheriting the spirit of open source, Spreading technology knowledge;)服務器
事物意指一組原子性的的SQL操做,即保證一組 SQL 語句要麼所有執行,要麼所有不執行;markdown
一個經典的案例銀行轉帳: 小知轉帳100元給小識,操做步驟以下架構
假設 有張金額表 money,對應SQL語句以下併發
如上語句就是 一次原子性操做,begin
爲開啓事物, commit
爲提交事物;假設沒有begin 和 commit ,在執行語句3的時候發生了斷電,小知的帳號金額扣除了100,但小識的金額卻沒有加上100,這就形成了數據的不一致,故事物在SQL中佔有主導性地位,特別是關於金額類操做;學習事物必須知足4個條件(ACID), 原子性(Atomicity,或稱不可分割性)、一致性(Consistency)、隔離性(Isolation,又稱獨立性)、持久性(Durability)。ide
原子性的概念比較簡單,就是事物被當初一個最小的單位,其不可分割,而且整個事物中的操做要麼所有失敗,要麼所有成功;oop
一致性 的意思就是 數據從一種狀態轉移至另外一種狀態,其數據完整沒有被破壞;如上例子小知扣除100元后,小識帳號金額沒有增長100,這就是狀態轉移後破壞了數據的一致性;
隔離性是指,一個事物在作出修改後至到事物提交前,其它的事物是不可見的;如上例子小知帳號有500元 扣除100元后, 假設有另一個事物參與進來,其是不能看見小知帳號爲400元,應該是500元;
持久性的概念更加簡單,即一旦事物提交,則數據修改操做永久保存到數據庫中;若是服務器發生故障則不會對持久化的數據產生任何影響;
mysql 中 經常使用 的就是 begin commit rollback 三個語句;
事物的隔離級別在每種數據庫的存儲引擎中都不同,通常是提交讀,但mysql使用InnoDB 時 是可重複度;
讀未提交
(read uncommited) 即事物修改後語句後並無提交,其修改的內容對其它事物是可見的,此時就會出現髒讀,如上例子 小知帳號500扣除 100 元 ,被其它事物讀看見讀取了400元,就出現了髒度;因此讀未提交在實際生產環境中基本不會使用到讀已提交
(read commited) 即一個事物只能讀取到另外一個事物已經提交後的數據;如上例子假設小知帳號金額500元, 小知帳號金額扣除100,小識帳號金額 加100,事物提交後,另外一個事物讀取小知帳號金額400;可重複讀
(repeatable read)即同一個事物屢次讀取的數據先後一致;如上例子,小知帳號500元,當執行如上操做事物完成後,另外一個事物讀取n次小知的帳號都是400元;可串行化
(serializable)即在每行的數據上都加上一行讀鎖,會致使鎖競爭問題,數據庫性能會下降;事物的最高級別;實際生產環境中也不多用到;mysql 中可使用 set transction 來設置 事物的隔離級別 即(read-uncommitted、read-committed、repeatable-read 和 serializable)
-- mysql 5版本
select @@tx_isolation;
set tx_isolation = 'read-uncommitted';
-- mysql 8版本
select @@transaction_isolation;
set transaction_isolation = '';
複製代碼
髒讀
:事務A讀取了事務B更新的數據,而後B回滾操做,那麼A讀取到的數據是髒數據不可重複讀
:事務 A 屢次讀取同一數據,事務 B 在事務A屢次讀取的過程當中,對數據做了更新並提交,致使事務A屢次讀取同一數據時,結果 不一致。幻讀
:A將數據庫中的數據進行修改,可是B就在這個時候插入了一條數據,當A改完後發現還有一條記錄沒有改過來,這就叫幻讀。因此幻讀針對插入語句;mysql 的 InnoDB 經過 多版本併發控制 (MVCC) 解決了幻讀問題;
一張顧客表,建表語句以下
CREATE TABLE `customer` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`customer_name` varchar(255) DEFAULT NULL COMMENT '顧客名稱',
`gender` varchar(255) DEFAULT NULL COMMENT '性別',
`telephone` varchar(255) DEFAULT NULL COMMENT '電話號碼',
`register_time` timestamp NULL DEFAULT NULL COMMENT '註冊時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8 COMMENT='顧客表';
複製代碼
提交事物示例
begin;
INSERT INTO `zszxz`.`customer`(`customer_name`, `gender`, `telephone`, `register_time`) VALUES ('知識追尋者', '男', '9991', NULL);
commit;
複製代碼
此時 數據庫中會增長一條數據;
回滾示例
begin;
INSERT INTO `zszxz`.`customer`(`customer_name`, `gender`, `telephone`, `register_time`) VALUES ('知識追尋者', '男', '9991', NULL);
rollback;
複製代碼
此時數據中並無添加新數據
實際上Mysql 中每次的事物操做默認都是自動提交(AUTOCOMMIT) , 即每條語句操做都會自動提交;
讀者可使用 以下 語句查看 mysql 的 AUTOCOMMIT 是否 開啓
SHOW VARIABLES LIKE 'AUTOCOMMIT'
複製代碼
操做示例以下:
使用以下語句能夠對 自動提交進行設置
關注知識追尋者: