国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

淺談MySQL的事務和ACID

數(shù)據(jù)庫 MySQL
所謂事務(Transaction),就是通過確保成批的操作要么完全執(zhí)行,要么完全不執(zhí)行,來維護數(shù)據(jù)庫的完整性。

所謂事務(Transaction),就是通過確保成批的操作要么完全執(zhí)行,要么完全不執(zhí)行,來維護數(shù)據(jù)庫的完整性。舉一個爛大街的例子:A 向 B 轉賬 1000 元,對應的 SQL 語句為:(沒有顯式定義事務)

  1. UPDATE deposit_table set depositdeposit = deposit - 1000 WHERE name = 'A'
  2. UPDATE deposit_table set depositdeposit = deposit + 1000 WHERE name = 'B'

運行后的結果如下:

  1. mysql> SELECT * FROM deposit_table; 
  2. +------+---------+ 
  3. | name | deposit | 
  4. +------+---------+ 
  5. | A    |    3000 | 
  6. | B    |    5000 | 
  7. +------+---------+ 

這樣做可能遇到問題,比如執(zhí)行完第一條語句之后,數(shù)據(jù)庫崩潰了,最后的結果就可能會是這樣(有待商榷,取決于下一條 SQL 有沒有被寫入日志):

  1. +------+---------+ 
  2. | name | deposit | 
  3. +------+---------+ 
  4. | A    |    2000 | 
  5. | B    |    5000 | 
  6. +------+---------+ 

A 的 1000 塊錢平白無故消失了,這肯定不合適。事務就是為了解決類似的問題而出現(xiàn)的,如果使用事務來處理轉賬,對應的 SQL 就是:

  1. START TRANSACTION; 
  2. UPDATE deposit_table set depositdeposit = deposit - 1000 WHERE name = 'A'
  3. UPDATE deposit_table set depositdeposit = deposit + 1000 WHERE name = 'B'
  4. COMMIT; 

僅僅是在這原先的兩條 SQL 語句前后加上了 START TRANSACTION 和 COMMIT ,就可以保證即使轉賬操作失敗,A 的余額也不會減少。

仔細想一想發(fā)現(xiàn)這個例子不是特別合適,因為數(shù)據(jù)庫的故障恢復技術(以后會談到)會影響最終的結果,也不容易模擬這種故障,最后結果只能靠猜 : ) 但我也想不出其它更加合適的例子。

接下來就詳細討論事務的一些特性和(某些)實現(xiàn)細節(jié)。

ACID

  • A:Atomicity(原子性)
  • C:Consistency(一致性)
  • I:Isolation(隔離性)
  • D:Durability(持久性)

1. Atomicity(原子性)

先談兩個重要的概念:提交(commit)和回滾(rollback),當我們執(zhí)行提交操作后,將對數(shù)據(jù)庫進行永久性的修改,執(zhí)行回滾操作,意味著數(shù)據(jù)庫將撤銷正在進行的所有沒有提交的修改。注意這里的永久性并不意味著事務一完成就把數(shù)據(jù)刷到磁盤上,即使沒有刷入磁盤,MySQL 也有日志機制來保證修改不會丟失。

事務是支持提交和回滾的工作單元,原子性,就是說事務對數(shù)據(jù)庫進行多次更改時,要么在提交事務的時候所有更改都成功,要么在回滾事務的時候撤銷所有更改。這是官方文檔的表述,但有的人似乎錯誤理解了 commit 語句,實際上,哪怕事務里某一語句出現(xiàn)了錯誤,一旦你執(zhí)行 commit,前面正常的修改仍然會被提交,MySQL 不會自動判斷事務中的 SQL 執(zhí)行成功與否。

我們接下來用例子來看看 commit 和 rollback:

  1. mysql> SELECT * FROM deposit_table; 
  2. +------+---------+ 
  3. | name | deposit | 
  4. +------+---------+ 
  5. | A    |    2000 | 
  6. | B    |    6000 | 
  7. +------+---------+ 
  8. 2 rows in set (0.04 sec) 
  1. mysql> 
  2. START TRANSACTION; 
  3. INSERT INTO deposit_table VALUES('C', 7000); 
  4. INSERT INTO deposit_table VALUES('D', 8000); 
  5. #再次插入 D,由于主鍵的唯一性,該語句會執(zhí)行失敗 
  6. INSERT INTO deposit_table VALUES('D', 9000); 
  7. COMMIT; #提交事務 
  8.  
  9. Query OK, 0 rows affected (0.00 sec) 
  10.  
  11. Query OK, 1 row affected (0.00 sec) 
  12.  
  13. Query OK, 1 row affected (0.00 sec) 
  14.  
  15. 1062 - Duplicate entry 'D' for key 'PRIMARY' 
  16. Query OK, 0 rows affected (0.07 sec) 
  1. mysql> SELECT * FROM deposit_table; 
  2. +------+---------+ 
  3. | name | deposit | 
  4. +------+---------+ 
  5. | A    |    2000 | 
  6. | B    |    6000 | 
  7. | C    |    7000 | 
  8. | D    |    8000 | 
  9. +------+---------+ 
  10. 4 rows in set (0.04 sec) 

我們可以看到,在執(zhí)行 INSERT INTO deposit_table VALUES('D', 9000) 的時候,由于前一條語句已經插入了 D,所以這一句 SQL 語句執(zhí)行失敗,報出 1062 - Duplicate entry 'D' for key 'PRIMARY' 錯誤,但執(zhí)行 COMMIT后,前面的修改仍然得到了提交,這顯然是不符合我們的預期的。

注意:如果你是使用 Navicat 的查詢界面,將執(zhí)行不到 COMMIT 語句,只能執(zhí)行到報錯的地方,建議使用命令行來執(zhí)行。

所以在實際情況中,我們需要根據(jù) MySQL 的錯誤返回值來確定,是使用 ROLLBACK 還是 COMMIT 。就像這樣:

  1. # 創(chuàng)建一個存儲過程 
  2. CREATE DEFINER=`root`@`localhost` PROCEDURE `insert_test`() 
  3. BEGIN 
  4.     # 創(chuàng)建一個標志符,出現(xiàn)錯誤就將其置為 1 
  5.     DECLARE err_flg INTEGER; 
  6.     DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET err_flg = 1
  7.  
  8.     START TRANSACTION; 
  9.         INSERT INTO deposit_table VALUES('C', 7000); 
  10.                 INSERT INTO deposit_table VALUES('D', 8000); 
  11.                 INSERT INTO deposit_table VALUES('D', 9000); 
  12.          
  13.         # 發(fā)生錯誤,回滾事務 
  14.         IF err_flg = 1 THEN 
  15.             SELECT 'SQL Err Invoked'; # 錯誤提示信息 
  16.             ROLLBACK; 
  17.             SELECT * FROM deposit_table; 
  18.         # 沒有發(fā)生錯誤,直接提交 
  19.         ELSE 
  20.             SELECT 'TRANSACTION Success'; 
  21.             COMMIT; 
  22.             SELECT * FROM deposit_table; 
  23.         END IF; 
  24.      
  25. END 

接下來我們調用該存儲過程:

  1. mysql> call insert_test(); 
  2. +-----------------+ 
  3. | SQL Err Invoked | 
  4. +-----------------+ 
  5. | SQL Err Invoked | 
  6. +-----------------+ 
  7. 1 row in set (0.04 sec) 
  8.  
  9. +------+---------+ 
  10. | name | deposit | 
  11. +------+---------+ 
  12. | A    |    2000 | 
  13. | B    |    6000 | 
  14. +------+---------+ 
  15. 2 rows in set (0.09 sec) 
  16.  
  17. Query OK, 0 rows affected (0.00 sec) 

結果里打印出了錯誤信息 SQL Err Invoked 表的內容也沒有更改,表明我們的 ROLLBACK 成功回滾了事務,達到我們的預期。如果你是使用其他語言調用 MySQL 的接口,也只需要獲取錯誤標志,相應的執(zhí)行 ROLLBACK 或者 COMMIT 。

2. Consistency(一致性)

官網給出的解釋如下:

The database remains in a consistent state at all times — after each commit or rollback, and while transactions are in progress. If related data is being updated across multiple tables, queries see either all old values or all new values, not a mix of old and new values.

翻譯過來就是:在每次提交或回滾之后以及正在進行的事務處理期間,數(shù)據(jù)庫始終保持一致狀態(tài),如果跨多個表更新了相關數(shù)據(jù),則查詢將看到所有舊值或所有新值,而不是新舊值的混合。

舉個例子:

  1. # 表 a,b 的定義略過 
  2. START TRANSACTION; 
  3. UPDATE a SET name = 'a_new' WHERE name = 'a_old'
  4. UPDATE b SET name = 'b_new' WHERE name = 'b_old'
  5. COMMIT; 

這個例子里的一致性,就是說,如果此時有查詢 SELECT a.name, b.name FROM a, b; 得到的結果要么是 a_old b_old (表明事務已回滾或者正在執(zhí)行),要么是 a_new b_new (表明事務已經成功提交),而不會出現(xiàn) a_old b_new以及 a_new b_old 這兩種情況。

有的博客將一致性解釋為“數(shù)據(jù)符合現(xiàn)實世界中的約束,比如唯一性約束等等。” 我個人還是傾向于官方文檔的解釋,這點見仁見智吧,糾結這些概念意義不大。

3. Isolation(隔離性)

事務的隔離性是說,事務之間不能互相干擾,也不能看到彼此的未提交數(shù)據(jù)。這種隔離是通過鎖機制實現(xiàn)的。我們在操作系統(tǒng)里也了解過,使用鎖,往往就意味著并發(fā)性能的下降,因為可能會發(fā)生阻塞,甚至死鎖現(xiàn)象。

當然,用戶在確定事務確實不會相互干擾時,可以調整隔離級別,犧牲部分隔離性以提高性能和并發(fā)性,至于使用哪種隔離級別(isolation level)這就需要你自己做 trade off。

因為隔離性涉及的的內容很多,我把它放到下一篇文章詳細解釋。

4. Durability(持久性)

事務的持久性是說,一旦提交操作成功,該事務所做的更改就不會因為一些意外而丟失,比如電源斷電,系統(tǒng)崩潰等潛在威脅。MySQL 提供了很多機制,比如日志技術,doublewrite buffer等等。

MySQL 的日志恢復技術我將單獨寫一篇文章,這里說說 doublewrite buffer 技術。

雖然這個技術名字叫做 buffer,但實際上該緩沖區(qū)并不位于內存,而是位于磁盤。這可能聽起來很詭異——既然是把數(shù)據(jù)放入磁盤,為啥不直接寫入到 data file,反而多此一舉?

這是因為 InnoDB 的 Page Size 一般是 16kb,其數(shù)據(jù)校驗也是針對頁來計算的,在將數(shù)據(jù)刷入磁盤的過程中,如果發(fā)生斷電等故障,該頁可能只寫入了一部分(partial page write)。這種情況是 redo 日志無法解決的,因為 redo 日志中記錄的是對頁的物理操作,如果頁本身發(fā)生了損壞,再對其進行 redo 是沒有意義的。所以我們需要一個副本,在發(fā)生這種情況時還原該頁。

而且緩沖區(qū)是順序寫的,開銷相對隨機讀寫要小很多,所以 doublewrite 后,性能也不是降為原來的 50%。

二、事務中的常用語句

  • START TRANSACTION / BEGIN 顯式開啟一個事務
  • COMMIT 提交事務,永久性修改數(shù)據(jù)庫
  • SAVEPOINT 在事務里創(chuàng)建保存點
  • RELEASE SAVAPOINT 移除某保存點
  • ROLLBACK 回滾事務,撤回所有未提交的更改,事務會終止
  • ROLLBACK TO [SAVEPOINT] 回滾到給定保存點,但事務不終止,另外,該保存點后的行鎖不會被釋放,詳見SAVEPOINT, ROLLBACK TO SAVEPOINT, and RELEASE SAVEPOINT Statements
    InnoDB does not release the row locks that were stored in memory after the savepoint. (For a new inserted row, the lock information is carried by the transaction ID stored in the row; the lock is not separately stored in memory. In this case, the row lock is released in the undo.)
  • SET TRANSACTION 設置事務隔離級別
  • SET autocommit 0/1 是否自動提交(默認自動提交)

強調一下 autocommit 參數(shù),默認情況下,如果不顯式使用 START TRANSACTION / BEGIN ,MySQL 會把每一句 SQL 當做獨立的事務,舉個例子:

原來的表結構:

  1. mysql> SELECT * FROM deposit_table; 
  2. +------+---------+ 
  3. | name | deposit | 
  4. +------+---------+ 
  5. | A    |    2000 | 
  6. | B    |    6000 | 
  7. +------+---------+ 
  8. 2 rows in set (0.04 sec) 

新的存儲過程(僅僅刪除了 START TRANSACTION ):

  1. CREATE DEFINER=`root`@`localhost` PROCEDURE `insert_test`() 
  2. BEGIN 
  3.     #Routine body goes here... 
  4.     DECLARE err_flg INTEGER; 
  5.     DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET err_flg = 1
  6.  
  7.     # START TRANSACTION; 
  8.     INSERT INTO deposit_table VALUES('C', 7000); 
  9.     INSERT INTO deposit_table VALUES('D', 8000); 
  10.     INSERT INTO deposit_table VALUES('D', 9000); 
  11.          
  12.         IF err_flg = 1 THEN 
  13.             SELECT 'SQL Err Invoked'; 
  14.             ROLLBACK; 
  15.             SELECT * FROM deposit_table; 
  16.         ELSE 
  17.             SELECT 'TRANSACTION Success'; 
  18.             COMMIT; 
  19.             SELECT * FROM deposit_table; 
  20.         END IF; 
  21.      
  22. END 

調用的結果:

  1. mysql> call insert_test(); 
  2. +-----------------+ 
  3. | SQL Err Invoked | 
  4. +-----------------+ 
  5. | SQL Err Invoked | 
  6. +-----------------+ 
  7. 1 row in set (0.24 sec) 
  8.  
  9. +------+---------+ 
  10. | name | deposit | 
  11. +------+---------+ 
  12. | A    |    2000 | 
  13. | B    |    6000 | 
  14. | C    |    7000 | 
  15. | D    |    8000 | 
  16. +------+---------+ 
  17. 4 rows in set (0.28 sec) 
  18.  
  19. Query OK, 0 rows affected (0.21 sec) 

在這里,我們看到盡管確實執(zhí)行了 ROLLBACK,但 C 和 D 仍然插入到了 deposit_table 。這是因為沒有顯式標明事務,MySQL 會進行隱式事務,自動提交每次的修改,所以就無法進行回滾了。

 

責任編輯:趙寧寧 來源: tobe的囈語
相關推薦

2024-03-15 11:59:25

SQL數(shù)據(jù)庫ACID

2024-12-02 08:37:04

2010-09-08 15:55:20

SQL事務特性

2019-04-03 09:27:01

MySQLInnoDB務ACID

2019-01-29 09:36:10

MySQLACID特性

2024-12-30 13:58:14

2023-01-05 12:30:32

Redis

2021-09-17 12:50:10

MySQL數(shù)據(jù)庫ACID

2021-10-18 08:41:20

Redis ACID事務

2021-07-08 07:08:21

MySQL ACID 數(shù)據(jù)庫

2010-11-22 16:40:00

MySQL事務表

2021-10-03 21:41:13

RocketMQKafkaPulsar

2017-07-26 15:08:05

大數(shù)據(jù)分布式事務

2009-06-29 17:54:47

Spring事務隔離

2022-03-30 07:28:24

MySQL數(shù)據(jù)庫ACID

2021-11-29 07:24:08

ACID事務大數(shù)據(jù)

2025-11-20 10:18:11

2024-12-30 07:20:00

Redis數(shù)據(jù)庫MySQL

2018-09-06 14:53:39

數(shù)據(jù)庫事務隔離隔離級別

2021-09-27 07:11:18

MySQLACID特性
點贊
收藏

51CTO技術棧公眾號

午夜av在线播放| 亚洲人成伊人成综合网小说| 免费黄色福利视频| 一区二区三区 在线观看视频| 爆操欧美美女| 91av视频在线观看| 免费观看在线综合| 亚洲欧美日韩中文字幕一区二区三区| 亚州黄色一级| 国产视频自拍一区| 亚洲精品国产成人影院| 成熟了的熟妇毛茸茸| 欧美高清视频在线高清观看mv色露露十八 | 久久国产精品久久| 国产三级三级三级精品8ⅰ区| 韩国av网站在线| 91精品国产91久久久久久最新| 久久99精品视频| 一区二区三区不卡在线视频| 九九热精品视频在线播放| 免费观看日韩电影| 久草视频在线看| 日韩av电影手机在线观看| 99综合电影在线视频| 一区二区三区四区视频在线 | 欧美高清在线一区| аⅴ资源天堂资源库在线| 成人免费视频观看视频| 中文字幕一区二区三区久久网站| 99热成人精品热久久66| 亚洲国产另类久久精品| 999在线观看精品免费不卡网站| 性一爱一乱一交一视频| 蜜月aⅴ免费一区二区三区| 激情综合色播五月| 逼特逼视频在线| 亚洲国产精久久久久久| 欧美精品日韩| 伊人精彩视频| 欧美中文字幕精品| 欧美激情中文字幕一区二区| 福利一区二区免费视频| 吴梦梦av在线| 精品国精品国产| 久久天堂成人| 黄色网页在线观看| 国产一区二区三区四区五区在线 | 麻豆视频在线观看免费网站黄| 国产综合动作在线观看| 色偷偷成人一区二区三区91| 久久国产亚洲精品| julia京香一区二区三区| 国产成人精品在线| 亚洲日本在线视频观看| 杨幂一区二区三区免费看视频| 国产99午夜精品一区二区三区| 欧美激情免费看| 亚洲视频在线一区观看| 日本美女高潮视频| 久久夜色精品国产欧美乱| av电影在线观看一区| 55av亚洲| 国产精品无码久久久久| 蜜芽在线免费观看| 亚洲欧洲在线一区| 一区二区三区国产好| 女性隐私黄www网站视频| 久久亚洲春色中文字幕| 久久精品一区二区三区不卡牛牛| 国产高清日韩| 色国产在线视频| 9.1国产丝袜在线观看| 亚洲影院免费观看| 色偷偷综合网| 在线观看免费高清完整| 日本不卡久久| 国产午夜精品久久久| 99久久99久久免费精品蜜臀| 国产免费999| 欧美亚洲第一区| 亚洲成a人片在线不卡一二三区| 国产精品不卡| 国产福利视频在线观看| 男女激烈动态图| 九九热最新视频//这里只有精品| 日一区二区三区| 99精品视频在线观看| 久久综合五月天婷婷伊人| 久久精品久久综合| 国外成人在线直播| 国产精品第一页第二页第三页| 西野翔中文久久精品字幕| 在线看片你懂得| 日本一区二区三区www| 亚洲最大中文字幕| 中文字幕日韩一区二区| 亚洲综合激情在线| 成年男女免费视频网站不卡| 日本www.色| 国产精品三区在线| 中文字幕欧美精品日韩中文字幕| 一区二区三区成人在线视频| 久久精品30| 五月亚洲婷婷| 北岛玲一区二区三区| 青青青在线观看视频| 国产精品欧美一区二区| 亚洲精品一区二区三区精华液| 久久久久九九视频| 欧美午夜影院| 99国内精品久久久久| 青青免费在线视频| 青青草视频在线免费播放| 91久久国产婷婷一区二区| 亚洲一级一级97网| 色综合久久久久综合| www.亚洲国产| 亚洲精一区二区三区| 日韩一级淫片| 中文字幕在线播放网址| 国产精品黄页网站在线播放免费| 手机看片福利永久国产日韩| 97成人超碰免| 亚洲美女久久久| 黑人与娇小精品av专区| 欧美激情福利| 欧美日本韩国一区二区| 日本www在线视频| 91久久精品国产91久久性色tv| 国产精品久久久久一区| 99精品国产福利在线观看免费| 婷婷激情成人| 免费人成在线观看播放视频| 免费看污污网站| 国产伦精品一区二区三区四区视频 | 亚洲天堂1区| 国产小视频在线| 成人精品视频一区二区| 欧美男人的天堂| 欧美性黄网官网| 国产成a人无v码亚洲福利| 婷婷精品进入| 伊人精品综合| 在线免费三级电影网站| 激情福利在线| siro系绝美精品系列| 丁香六月激情婷婷| 精品一区二区久久久久久久网站| 97国产精品人人爽人人做| 日韩精品视频免费| 91福利小视频| 亚洲老妇xxxxxx| 久久综合久久久久88| 国产精品综合| 亚洲一区二区三区无吗| 99久久香蕉| 欧美男男gaygay1069| fc2ppv国产精品久久| 三区在线视频| 免费福利影院| 97在线资源在| 久久久久久久久久福利| 中文字幕中文字幕在线中心一区| 岛国一区二区三区高清视频| 国产不卡精品视男人的天堂| 久久夜色精品亚洲噜噜国产mv| 精品亚洲一区二区三区四区五区| 91黄色免费网站| 五月天精品一区二区三区| 中文字幕一区二区三中文字幕| av午夜一区麻豆| 久久 天天综合| 日日摸夜夜添夜夜添国产精品| 自拍偷拍欧美专区| 日韩欧美三级| 精品九九在线| 日本韩国欧美超级黄在线观看| 91精品国产自产观看在线 | 日韩av男人的天堂| 欧美成人精品在线| 中文字幕最新精品| 亚洲欧美日韩第一区| 亚洲国产精品专区久久| 日韩美女天天操| 亚洲成人国产精品| 亚洲第一偷拍网| 亚洲国产日韩欧美在线动漫| 精品三级av在线| 精品久久久久av影院| 精品欧美一区二区久久 | 在线视频日韩精品| 正在播放国产一区| 深夜福利一区二区| 日韩在线www| 欧美风情在线观看| 欧美一级高清免费播放| 日本精品va在线观看| 国产一区在线播放| 懂色av一区二区三区在线播放| 欧美日韩国产综合视频在线|