SQL-SQL事物操做

一 前言

本篇內容是關於SQL事物知識,主要包括事物的概念,ACID,幻讀,不可重複度,髒度等內容;mysql

學習本篇的基礎是知識追尋者發過的SQL系列文章(公衆號讀者直接在專欄裏面找便可sql

本套教程數據庫

公衆號:知識追尋者json

知識追尋者(Inheriting the spirit of open source, Spreading technology knowledge;)服務器

二 事物的概念

事物意指一組原子性的的SQL操做,即保證一組 SQL 語句要麼所有執行,要麼所有不執行;markdown

一個經典的案例銀行轉帳: 小知轉帳100元給小識,操做步驟以下架構

  1. 銀行查詢小知帳號金額大於等於100
  2. 銀行從小知帳號扣除100元
  3. 銀行將小識帳號金額增長100元

假設 有張金額表 money,對應SQL語句以下併發

  1. begin;
  2. select balance from money where username = 'xiaozhi' and balance > = '100';
  3. update money set balance = balance - 100 where username = 'xiaozhi';
  4. update money set balance = balance + 100 where username = 'xiaoshi';
  5. commit;

如上語句就是 一次原子性操做,begin 爲開啓事物, commit爲提交事物;假設沒有begin 和 commit ,在執行語句3的時候發生了斷電,小知的帳號金額扣除了100,但小識的金額卻沒有加上100,這就形成了數據的不一致,故事物在SQL中佔有主導性地位,特別是關於金額類操做;學習事物必須知足4個條件(ACID), 原子性(Atomicity,或稱不可分割性)、一致性(Consistency)、隔離性(Isolation,又稱獨立性)、持久性(Durability)。ide

三 ACID

3.1 原子性

原子性的概念比較簡單,就是事物被當初一個最小的單位,其不可分割,而且整個事物中的操做要麼所有失敗,要麼所有成功;oop

3.2 一致性

一致性 的意思就是 數據從一種狀態轉移至另外一種狀態,其數據完整沒有被破壞;如上例子小知扣除100元后,小識帳號金額沒有增長100,這就是狀態轉移後破壞了數據的一致性;

3.3 隔離性

隔離性是指,一個事物在作出修改後至到事物提交前,其它的事物是不可見的;如上例子小知帳號有500元 扣除100元后, 假設有另一個事物參與進來,其是不能看見小知帳號爲400元,應該是500元;

3.4 持久性

持久性的概念更加簡單,即一旦事物提交,則數據修改操做永久保存到數據庫中;若是服務器發生故障則不會對持久化的數據產生任何影響;

四 事物的簡單操做

4.1 事物語句

  • bengin 或者 start transction 表示開啓事物;
  • commit也可使用 commit work 表示提交事物,提交事物後數據就持久化了;
  • rollback 也可使用 rollback work 表示回滾事物,即我後悔剛剛的SQL操做,一切不算數;
  • savepoint identifier,savepoint 容許在事務中建立一個保存點,一個事務中能夠有多個 savepoint ;
  • release savepoint identifier 刪除一個事務的保存點,當沒有指定的保存點時,執行該語句會拋出一個異常;
  • rollback to identifier 事務回滾到保存點;
  • set transction 用來設置事務的隔離級別;

mysql 中 經常使用 的就是 begin commit rollback 三個語句;

4.2 事物的隔離級別

事物的隔離級別在每種數據庫的存儲引擎中都不同,通常是提交讀,但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 = '';

複製代碼

4.3 事物併發問題

  • 髒讀:事務A讀取了事務B更新的數據,而後B回滾操做,那麼A讀取到的數據是髒數據
  • 不可重複讀:事務 A 屢次讀取同一數據,事務 B 在事務A屢次讀取的過程當中,對數據做了更新並提交,致使事務A屢次讀取同一數據時,結果 不一致。
  • 幻讀:A將數據庫中的數據進行修改,可是B就在這個時候插入了一條數據,當A改完後發現還有一條記錄沒有改過來,這就叫幻讀。因此幻讀針對插入語句

mysql 的 InnoDB 經過 多版本併發控制 (MVCC) 解決了幻讀問題;

4.3 實際操做

一張顧客表,建表語句以下

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;
複製代碼

此時數據中並無添加新數據

4.3 mysql 事物的自動提交

實際上Mysql 中每次的事物操做默認都是自動提交(AUTOCOMMIT) , 即每條語句操做都會自動提交;

讀者可使用 以下 語句查看 mysql 的 AUTOCOMMIT 是否 開啓

SHOW VARIABLES LIKE 'AUTOCOMMIT'
複製代碼

操做示例以下:

tXlB9A.png

使用以下語句能夠對 自動提交進行設置

  • SET AUTOCOMMIT=0 (0 或者OFF 表示禁止自動提交)
  • SET AUTOCOMMIT=1 (1或者ON開啓自動提交)

關注知識追尋者: tLeP2D.png

相關文章
相關標籤/搜索