[MySQL光速入門]020 事務

TCL 事務控制語言

SQL的四種語言

  1. DDL(Data Definition Language)數據庫定義語言 建表, 建庫, 修改表結構
  2. DML(Data Manipulation Language)數據操縱語言 增刪改查, select, insert, update, delete
  3. DCL(Data Control Language)數據庫控制語言 修改用戶權限, 重置密碼
  4. TCL(Transaction Control Language)事務控制語言 建立事務, 回滾

什麼是事務

一組SQL語句組成的執行單元, 這一組SQL語句, 要麼所有執行, 要麼所有不執行.
複製代碼

舉例sql

  • 郭靖向黃蓉轉帳(交工資)
  • 郭靖這個月發了5000, 銀行卡餘額5000
  • 黃蓉, 銀行卡餘額5000,000
  • update set 郭靖的銀行卡餘額 - 5000;
  • update set 黃蓉的銀行卡餘額 + 5000;
  • 咱們須要兩條SQL語句都要成功, 不然咱們寧願沒執行過, 因此就是, 要麼所有執行, 要麼所有不執行.

事務:數據庫

  • 事務由單獨單元的一個或多個SQL語句組成
  • 在這個單元中,每一個MySQL語句是相互依賴的
  • 而整個單獨單元做爲一個不可分割的總體
  • 若是單元中某條SQL語句一旦執行失敗或產生錯誤,整個單元將會回滾
  • 全部受到影響的數據將返回到事物開始之前的狀態
  • 若是單元中的全部SQL語句均執行成功,則事物被順利執行

舉例2:session

  • 軟件安裝, 會有不少下一步, 若是點擊取消, 則所有回滾.

image.png

事務 vs 存儲引擎(表類型)

什麼是存儲引擎(表類型):

  • MySQL中的數據用各類不一樣的技術存儲在文件(或者內存)中。
  • 這些技術中的每一種技術都使用不一樣的存儲機制、索引技巧、鎖定水平而且最終提供普遍的不一樣的功能和能力。
  • 經過選擇不一樣的技術,你可以得到額外的速度或者功能,從而改善你的應用的總體功能。
  • 若是你在研究大量的臨時數據,你也許須要使用內存MySQL存儲引擎(memory)。
  • 內存存儲引擎可以在內存中存儲全部的表格數據。
  • 又或者,你須要一個支持事務處理的數據庫(以確保事務處理不成功時數據的回退能力), 那就用innodb
  • 這些不一樣的技術以及配套的相關功能在 MySQL中被稱做存儲引擎(也稱做表類型)。

爲何須要多個存儲引擎?

  • 每種引擎都有各自的優點和不足, 沒有一種完美的存儲引擎
  • 因此MySQL能夠針對不一樣的表, 選擇不一樣的存儲引擎
  • 就像雷達圖

image.png

image.png

image.png

如何設置表的存儲引擎?

create table tb (id int) engine = myisam;
-- 或者
alter table tb engine = memory;
複製代碼

查看全部存儲引擎

show engines;
複製代碼

image.png

innodb:
  • 支持事務, 查詢速度沒有myisam快, 容量沒有myisam大
myisam:
  • 速度快, 容量大, 不支持事務
memory:
  • 速度超快, 容量取決於內存, 因此比較小, 不支持事務

事務的屬性(ACID)

  • 原子性 atomicity併發

    • 事務是一個總體, 不可分割, (由於原子不可再分)
    • 要麼所有執行, 要麼所有不執行
  • 一致性 consistencyoop

    • 參見能量守恆定律
    • 能量既不會憑空產生,也不會憑空消失,只能從一個物體傳遞給另外一個物體,從一種形式變成另外一種形式, 在變換過程當中, 系統的總能量保持不變。
    • 事務必須是數據庫從一個一致性狀態到另外一個一致性狀態
    • 好比轉帳(事務)先後, 郭靖, 黃蓉的銀行卡餘額之和是固定不變的.
  • 隔離性(isolation)post

    • 一個事務的執行, 不受其餘事務的干擾
    • 郭靖向黃蓉轉帳的時候, 黃藥師也能夠向黃蓉轉帳(須要配置隔離級別)
  • 持久性(durability)性能

    • 事務一旦成功, 不可撤銷
    • 刪除就是一個事務, 刪庫只能跑路
    • 轉帳成功, 不能撤銷, 除非對方再轉給你, 這是另外一個事務

事務一般包括多條SQL語句(DML), 其實單獨的DML語句, 也是一個事務測試

  • 隱式事務(自動提交)ui

    • 事務沒有明顯的開啓和結束標記
    • 好比 insert,update,delete
  • 顯式事務atom

    • 數據具備明顯的開始和結束標記
    • 前提, 必須設置自動提交功能爲禁用 set autocommit = 0;
    • 不然每條語句都是一個事務

建立事務

查看變量

show variables like 'autocommit';
-- 或者
select @@autocommit;
複製代碼

關閉自動提交

-- 當前會話有效
set autocommit = 0; 
-- 或者
set session autocommit = 0; 
-- 或者
set @@autocommit = 0;
-- 或者
set @@session.autocommit = 0;
複製代碼

事務的建立

  1. 開啓事務

    set autocommit = 0;
    start transaction; // 可選
    複製代碼
  2. 編寫事務中的sql語句(select, insert, update, delete) 不包括DDL(create, drop, alter)

  3. 結束事務

    • 提交事務 commit
    • 回滾事務 rollback

事務實操

drop table if exists test_tb;

CREATE TABLE `test_tb` (
  `id` int(5) unsigned NOT NULL,
  `age` tinyint(5) unsigned NOT NULL,
  `account` int(11) unsigned NOT NULL,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=innodb DEFAULT CHARSET=utf8;

INSERT INTO `test_tb`(`id`, `age`, `account`, `name`) VALUES (1, 11, 5000, '張三');
INSERT INTO `test_tb`(`id`, `age`, `account`, `name`) VALUES (2, 12, 5000, '李四');
複製代碼

事務正常提交

set autocommit = 0;
start TRANSACTION;
update test_tb set account = account - 4000 where name = '張三';
update test_tb set account = account + 4000 where name = '李四';
commit;
複製代碼

事務回滾

set autocommit = 0;
start TRANSACTION;
update test_tb set account = account - 4000 where name = '張三';
update test_tb set account = account + 4000 where name = '李四';
rollback;
複製代碼

同時運行多個事務的時候...

對於同時運行的多個事務, 若是沒有采用必要的隔離機制, 就會致使各類併發問題

事務衝突.png

髒讀

  • 對於兩個事務T1,T2, T1讀取了已經被T2更新可是尚未被提交的字段以後
  • 若是T2回滾, T1讀取的內容就是臨時而且無效的
  • 好比, 有一天, 你查詢餘額, 發現多了100萬!
  • 你難以壓抑本身激動的心情, 給親朋好友挨個打電話, 約他們吃飯
  • 等打完電話, 再看餘額, 發現100萬又沒有了...
  • 原來是銀行把錢打錯了, 剛剛撤銷了以前的轉帳...

幻讀

  • 對於兩個事務T1,T2, T1從一個表中讀取了一些數據
  • 而後T2在該表中插入/刪除了一些新的行以後, 若是T1再次讀取同一個表, 就會多出/少了幾行.
  • 彷彿出現了幻覺
  • 好比, 你看見屋裏只有兩我的, 乾乾巴巴, 麻麻賴賴, 一點都不圓潤
  • 知道吃得少, 因此你想耍一下大方
  • 就說"我今天請全部人吃飯!"
  • 剛說完, 又從外面進來兩個, 他們問你:"你說請全部人吃飯? 好的! 好的!"
  • 你不敢相信本身的眼睛, 彷彿出現了幻覺...

image.png

不可重複讀

  • 對於兩個事務T1,T2, T1讀取了一個字段,
  • 而後T2更新了該字段並提交, T1再次讀取同一個字段, 值就不一樣了.
  • 好比上午你去淘寶買東西, 一個手機1999, 果斷下單
  • 到下午再看的時候, 手機已經發貨, 可是售價變成了1799
  • 發生悲劇的緣由是, 上午賣家修改了價格, 可是沒有提交, 下午已經提交了
  • 因此上午和下午, 你看到的價格不同...

數據庫事務的隔離性:

  • 數據庫系統必須具備隔離併發運行各個事務的能力, 使他們不會互相影響, 避免各類併發問題.
  • 一個事務與其餘事務隔離的程度稱爲隔離級別
  • 數據庫規定了多種事務隔離級別, 不一樣隔離級別對應不一樣的干擾程度
  • 隔離級別越高, 數據一致性越好, 但併發性越弱
  • 就像一次只作一件事, 沒有其餘事情的干擾, 確定不容易出錯, 可是效率也會比較低

4種隔離級別

  1. 讀未提交數據(read uncommitted)
    • 容許事務讀取未被其餘事務提交的變動
    • 髒讀, 不可重複讀幻讀, 都會出現
  2. 讀已提交數據(read commited)
    • 只容許事務讀取已經被其餘事務提交的變動, 能夠避免髒讀
    • 不可重複讀幻讀問題仍然可能出現
  3. 可重複讀(repeatable read)
    • 確保事務能夠從一個字段中讀取相同的值, 在這個事務持續期間, 禁止其餘事務對這個字段進行更新
    • 能夠避免髒讀不可重複讀, 可是幻讀問題讓然存在
  4. 串行化(serializable)
    • 確保事務能夠從一個表中讀取相同的行
    • 在這個事務持續期間, 禁止其餘事務對該表執行插入, 更新和刪除操做, 全部併發問題均可以免
    • 可是性能十分低下

image.png

MySQL支持以上所有四種事務隔離級別, 默認 repeatable read(可重複讀)

查看當前隔離級別

select @@tx_isolation;
-- 或者
show variables like "tx_isolation";
複製代碼

設置隔離級別

set session transaction isolation level repeatable read; // 當前會話
-- 或者
set global transaction isolation level repeatable read; // 全局
複製代碼

隔離級別驗證

感興趣的小夥伴們, 能夠測試一下各個隔離級別的不一樣 下面是測試須要時, 用到的數據

DROP TABLE IF EXISTS test;
CREATE TABLE test (
	id INT auto_increment PRIMARY KEY,
	NAME VARCHAR ( 10 ) NOT NULL,
	account INT ( 11 ) NOT NULL,
	age TINYINT ( 1 ) NOT NULL,
	sex CHAR ( 1 ) NOT NULL DEFAULT '男' 
);
INSERT INTO test ( NAME, account, age )
VALUES
	( '張三', 3000, 18 ),
	( '李四', 4000, 28 ),
	( '王五', 5000, 38 ),
	( '趙六', 6000, 48 ),
	( '孫七', 2000, 19 ),
	( '周八', 1000, 29 ),
	( '吳老九', 9000, 39 ),
	( '馮老十', 8000, 49 );
複製代碼

衝突的級別

髒讀、不可重複讀、幻讀的級別高低是:

髒讀 < 不可重複讀 < 幻讀

因此,設置了最高級別的serializable就不用在設置repeatable readread committed

回滾點(savepoint)

就像玩遊戲時的存盤點, 若是遊戲人物死了, 就會在存盤點復活

直接上例子, 以上面的數據爲例

set autocommit = 0;
start TRANSACTION;
update test set account = 9999 where id = 1;
SAVEPOINT a;
update test set account = 9999 where id = 2;
rollback to a;

select * from test;
複製代碼

image.png

快速跳轉

相關文章
相關標籤/搜索