mysql 数据库事务处理_MySQL数据库事务及其原理
基本概念
MySQL 事務(wù)主要用于處理操作量大,復(fù)雜度高的數(shù)據(jù)。
銀行轉(zhuǎn)賬是經(jīng)典的解釋事務(wù)的例子。用戶A給用戶B轉(zhuǎn)賬5000元主要步驟可以概括為如下兩步。
第一,賬戶A賬戶減去5000元;
第二,賬戶B賬戶增加5000元;
這兩步要么成功,要么全不成功,否則都會(huì)導(dǎo)致數(shù)據(jù)不一致。這就可以用到事務(wù)來保證,如果是不同銀行之間的轉(zhuǎn)賬還需要用到分布式事務(wù)。
事務(wù)的特性(ACID)
(1)在 MySQL 中只有使用了 Innodb 數(shù)據(jù)庫引擎的數(shù)據(jù)庫或表才支持事務(wù)。
(2)事務(wù)處理可以用來維護(hù)數(shù)據(jù)庫的完整性,保證成批的 SQL 語句要么全部執(zhí)行,要么全部不執(zhí)行。
(3)事務(wù)用來管理 insert,update,delete 語句。
原子性:構(gòu)成事務(wù)的的所有操作必須是一個(gè)邏輯單元,要么全部執(zhí)行,要么全部不執(zhí)行。
一致性:在事務(wù)開始之前和事務(wù)結(jié)束以后,數(shù)據(jù)庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預(yù)設(shè)規(guī)則。
隔離性:并發(fā)事務(wù)之間不會(huì)相互影響。
持久性:事務(wù)處理結(jié)束后,對數(shù)據(jù)的修改就是永久的,即便系統(tǒng)故障也不會(huì)丟失。事務(wù)執(zhí)行成功后必須全部寫入磁盤。
事務(wù)隔離性的實(shí)現(xiàn)原理
數(shù)據(jù)庫事務(wù)會(huì)導(dǎo)致臟讀、不可重復(fù)讀、幻讀等問題。
1、臟讀:事務(wù)還沒提交,他的修改已經(jīng)被其他事務(wù)看到。
2、不可重復(fù)讀:在一個(gè)事務(wù)內(nèi)讀取到了表中的某一行數(shù)據(jù),多次讀取結(jié)果不同。
3、幻讀:同一個(gè)事務(wù)突然發(fā)現(xiàn)他以前沒發(fā)現(xiàn)的數(shù)據(jù)。幻讀是前后讀取到表中的記錄總數(shù)不一樣,讀取到了其它事務(wù)插入的數(shù)據(jù)。
事務(wù)的隔離用是通過鎖機(jī)制實(shí)現(xiàn)的,不同于MyISAM使用表級(jí)別的鎖,InnoDB采用更細(xì)粒度的行級(jí)別鎖,提高了數(shù)據(jù)表的性能。InnoDB的鎖通過鎖定索引來實(shí)現(xiàn),如果查詢條件中有主鍵則鎖定主鍵,如果有索引則先鎖定對應(yīng)索引然后再鎖定對應(yīng)的主鍵(可能造成死鎖),如果連索引都沒有則會(huì)鎖定整個(gè)數(shù)據(jù)表。
MyISAM類型不支持事務(wù)處理等高級(jí)處理,而InnoDB類型支持。MyISAM類型的表強(qiáng)調(diào)的是性能,其執(zhí)行數(shù)度比InnoDB類型更快,但是不提供事務(wù)支持,而InnoDB提供事務(wù)支持以及外部鍵等高級(jí)數(shù)據(jù)庫功能。
數(shù)據(jù)庫鎖
1、悲觀鎖(更新多,查詢少時(shí)用)
如果我們采用悲觀鎖。就是我們在操作數(shù)據(jù)庫時(shí)采用悲觀的態(tài)度,認(rèn)為別人會(huì)在此時(shí)并發(fā)訪問數(shù)據(jù)庫。我們在查詢語句中select * from account where name=‘a(chǎn)aa’ for update; 等于加了排它鎖。當(dāng)A查詢余額的時(shí)候,select money from account where name=‘a(chǎn)aa’ forupdate; 增加了排它鎖,B查詢賬戶余額的時(shí)候, select money from account wherename=‘a(chǎn)aa’ forupdate; 也要求對數(shù)據(jù)庫加排它鎖,因?yàn)锳已經(jīng)拿到了排它鎖,導(dǎo)致B不能加鎖,所以B只有等待A執(zhí)行完畢,釋放掉鎖以后才能繼續(xù)操作。
2、樂觀鎖(更新少,查詢多時(shí)用)
如果我們采用樂觀鎖,就是我們在操作數(shù)據(jù)庫的時(shí)候會(huì)認(rèn)為沒有其它用戶并發(fā)訪問,但是樂觀鎖也不是完全樂觀的,樂觀鎖是采用版本號(hào)的方式進(jìn)行控制的。在數(shù)據(jù)庫表中有一列版本號(hào)。從數(shù)據(jù)庫中查詢的時(shí)候,將版本號(hào)也查詢過來,在進(jìn)行更新操作的時(shí)候,將版本號(hào)加1,查詢條件的版本號(hào)還是查詢過來的版本號(hào)。比如,A執(zhí)行查詢操作的時(shí)候,selectmoney,version from account where name=‘a(chǎn)aa’; 假設(shè)此時(shí)查詢到的版本號(hào)為0,A在進(jìn)行更新操作的時(shí)候 update account set money=money+100, version=version+1where name=‘a(chǎn)aa’ and version=0; 未提交時(shí)B來查詢,查詢到的版本號(hào)依然是 0,B也執(zhí)行更新操作update account set money=money+100,version=version+1 wherename=‘a(chǎn)aa’ and version=0;現(xiàn)在A提交了事務(wù),B再提交事務(wù)的時(shí)候發(fā)現(xiàn)版本號(hào)為 0的記錄沒有了,所以就避免了數(shù)據(jù)丟失的問題。不過這種情況也導(dǎo)致了多個(gè)用戶更新操作時(shí),只有一個(gè)用戶的更新被執(zhí)行。
3、行級(jí)鎖(為某一條記錄加鎖)
如果想對數(shù)據(jù)庫中的某條記錄加行級(jí)鎖,那么 where 條件后面必須為索引列。否則 for update加的都是表級(jí)鎖。行級(jí)鎖就是只對要訪問的當(dāng)前行加鎖,其他用戶訪問其它行記錄的時(shí)候可以訪問。 select * from accountwhere id=1 for update;
4、表級(jí)鎖(為一張表加鎖)
在查詢語句后增加 for update 時(shí),where 條件后不是索引列,那么此時(shí)都是表級(jí)鎖。select * fromaccount where name=‘a(chǎn)aa’ for update;
原子性、一致性和持久性實(shí)現(xiàn)原理
原子性、穩(wěn)定性和持久性是通過redo 和 undo 日志文件實(shí)現(xiàn)的,不管是redo還是undo文件都會(huì)有一個(gè)緩存我們稱之為redo_buf和undo_buf。同樣,數(shù)據(jù)庫文件也會(huì)有緩存稱之為data_buf。
undo記錄了數(shù)據(jù)在事務(wù)開始之前的值,當(dāng)事務(wù)執(zhí)行失敗或者ROLLBACK時(shí)可以通過undo記錄的值來恢復(fù)數(shù)據(jù)。
redo日志記錄數(shù)據(jù)修改后的值,可以避免數(shù)據(jù)在事務(wù)提交之前必須寫入到磁盤的需求,減少I/O。
事務(wù)操作
BEGIN; //開始事務(wù),掛起自動(dòng)提交
insert into t_cart_shopcart (user_id, sku_id, amount, shop_id, status) values(10001, 10001, 1, 10001, 0);
insert into t_cart_shopcart (user_id, sku_id, amount, shop_id, status) values(10001, 10002, 1, 10001, 0);
COMMIT; //提交事務(wù),恢復(fù)自動(dòng)提交
1
2
3
4
set autocommit = 0; //掛起自動(dòng)提交
insert into t_cart_shopcart (user_id, sku_id, amount, shop_id, status) values(10001, 10001, 1, 10001, 0);
insert into t_cart_shopcart (user_id, sku_id, amount, shop_id, status) values(10001, 10002, 1, 10001, 0);
COMMIT; //提交事務(wù)
set autocommit = 1; //恢復(fù)自動(dòng)提交
與50位技術(shù)專家面對面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的mysql 数据库事务处理_MySQL数据库事务及其原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oa部署mysql_oa系统部署
- 下一篇: mysql怎么使用sql语句查看表的编码