Mysql事务处理问题
今天和同學(xué)討論起數(shù)據(jù)庫事務(wù)處理的問題,感覺討論中明白了一些,有些知識(shí)看過了,但是沒有實(shí)際使用還是不理解。
事務(wù)處理就是將一系列操作當(dāng)做一個(gè)原子操作,要么全部執(zhí)行成功,如果執(zhí)行失敗則保留執(zhí)行期的狀態(tài)。通過提交和回滾機(jī)制來實(shí)現(xiàn)操作,如果全部執(zhí)行成功通過提交執(zhí)行commit結(jié)果就會(huì)記錄到數(shù)據(jù)庫中,如果執(zhí)行失敗通過回滾操作rollback將發(fā)生錯(cuò)誤之前的所有錯(cuò)誤消除,回退到原來狀態(tài)。
事務(wù)都應(yīng)該具備ACID特征。所謂ACID是Atomic(原子性),Consistent(一致性),Isolated(隔離性),Durable(持續(xù)性)四個(gè)詞的首字母所寫,下面以“銀行轉(zhuǎn)帳”為例來分別說明一下它們的含義:
原子性:組成事務(wù)處理的語句形成了一個(gè)邏輯單元,不能只執(zhí)行其中的一部分。換句話說,事務(wù)是不可分割的最小單元。比如:銀行轉(zhuǎn)帳過程中,必須同時(shí)從一個(gè)帳戶減去轉(zhuǎn)帳金額,并加到另一個(gè)帳戶中,只改變一個(gè)帳戶是不合理的。
一致性:在事務(wù)處理執(zhí)行前后,數(shù)據(jù)庫是一致的。也就是說,事務(wù)應(yīng)該正確的轉(zhuǎn)換系統(tǒng)狀態(tài)。比如:銀行轉(zhuǎn)帳過程中,要么轉(zhuǎn)帳金額從一個(gè)帳戶轉(zhuǎn)入另一個(gè)帳戶,要么兩個(gè)帳戶都不變,沒有其他的情況。
隔離性:一個(gè)事務(wù)處理對(duì)另一個(gè)事務(wù)處理沒有影響。就是說任何事務(wù)都不可能看到一個(gè)處在不完整狀態(tài)下的事務(wù)。比如說,銀行轉(zhuǎn)帳過程中,在轉(zhuǎn)帳事務(wù)沒有提交之前,另一個(gè)轉(zhuǎn)帳事務(wù)只能處于等待狀態(tài)。
持續(xù)性:事務(wù)處理的效果能夠被永久保存下來。反過來說,事務(wù)應(yīng)當(dāng)能夠承受所有的失敗,包括服務(wù)器、進(jìn)程、通信以及媒體失敗等等。比如:銀行轉(zhuǎn)帳過程中,轉(zhuǎn)帳后帳戶的狀態(tài)要能被保存下來。
注意Mysql支持的存儲(chǔ)引擎中,默認(rèn)為MyISAM,是不支持事務(wù)處理的,一般都有InnoDB,是支持事務(wù)型的。
(1)如果對(duì)一個(gè)表進(jìn)行操作的時(shí)候需要事務(wù)支持,需要配置存儲(chǔ)引擎為InnoDB等支持事務(wù)型的。
create table XX() engine=InnoDB;
(2)默認(rèn)情況下,mysql是自動(dòng)提交模式(autocommit=1),此時(shí)會(huì)在每一條語句執(zhí)行完畢后將所做修改立即提交,此時(shí)的commit相當(dāng)于沒用的,rollback只對(duì)前一句語句起作用,其實(shí)也沒用,一條mysql語句默認(rèn)也是原子操作,沒必要。
如果設(shè)置默認(rèn)事務(wù)處理,需要將自動(dòng)提交模式關(guān)閉即將autocommit設(shè)置為0.
set autocommit=0;???? 設(shè)置模式為關(guān)閉
select @@autocommit;? 查看值是否已經(jīng)改變
注意,如果在客戶端設(shè)置的話,設(shè)置完,之后斷掉連接后再重連又恢復(fù)默認(rèn)設(shè)置。每個(gè)客戶端只能設(shè)置客戶自己的。
(3)如果自動(dòng)提交模式是打開的,則需使用語句:
start transaction;?? 開始事務(wù)處理
XX1;
XX2;
commit;? /? rollback;
來開始事務(wù)處理;而如果設(shè)置為關(guān)閉,則無需使用start transaction,連續(xù)語句就為事務(wù)指導(dǎo)rollback或者commit。
(4)注意創(chuàng)建、改變、刪除數(shù)據(jù)庫或者其中的數(shù)據(jù)定義語言以及鎖有關(guān)的都不能成為事務(wù)的一部分,如下面:
start transaction; insert into test1 values("8"); create table test2(i int); insert into test1 values("8"); rollback;
執(zhí)行一個(gè)事務(wù)處理,當(dāng)執(zhí)行到要?jiǎng)?chuàng)建表時(shí),mysql會(huì)自動(dòng)提交,然后再執(zhí)行創(chuàng)建語句。如果test1的i為主鍵,則第三條語句出錯(cuò),回滾時(shí)test1還是插入成功,且創(chuàng)建了表test2.
(5)python中使用數(shù)據(jù)庫,最好采用這種形式,
import MySQLdbtry:conn = MySQLdb.connect(host="localhost",user="root",passwd="your passwd",db="dbName") except MySQLdb.Error,e:print "Mysql Error %d: %s" % (e.args[0], e.args[1])else:pass #conn.close()
try:cur=conn.cursor()cur.execute('set autocommit=0') #cur.execute('start transaction')cur.execute('insert into test1 values("8")')cur.execute('insert into test1 values("8")') except MySQLdb.Error,e:conn.rollback() print "Mysql Error %d: %s" % (e.args[0], e.args[1])else:conn.commit()cur.close()conn.close()
(6)并行處理問題
Mysql是一個(gè)多用戶的系統(tǒng),有多用戶在同一時(shí)間訪問統(tǒng)一數(shù)據(jù)表,MySIAM采用的是數(shù)據(jù)表級(jí)的鎖定標(biāo)記,來保證同一時(shí)間只有一個(gè)用戶訪問此表;Innodb采用了數(shù)據(jù)行級(jí)的訪問機(jī)制,即兩個(gè)用戶可以對(duì)同一個(gè)表中不同行的數(shù)據(jù)同時(shí)進(jìn)行修改,而如果是同一行,則先來的用戶先鎖住此行,操作結(jié)束釋放鎖后,下一個(gè)用戶才能操作。
(7)事務(wù)處理的隔離性問題
InnoDB默認(rèn)的隔離級(jí)別是repeatable read,如果某個(gè)用戶兩次執(zhí)行同一個(gè)select語句,其結(jié)果是可重復(fù)的,如果在事務(wù)期間有用戶對(duì)所要讀取的數(shù)據(jù)進(jìn)行了操作,那么也不會(huì)有顯示,比如一個(gè)存儲(chǔ)引擎為innodb的表,如果有一個(gè)客戶用事務(wù)來select讀取表數(shù)據(jù),另一個(gè)用戶此時(shí)對(duì)表做了一個(gè)插入之類的操作,第一個(gè)用戶再進(jìn)行同樣的select讀取時(shí),顯示數(shù)據(jù)是沒有變化的。
(8)多語句操作非原子操作
如上面(6)中會(huì)出現(xiàn)一個(gè)問題,如果是一個(gè)事務(wù)操作,讀取數(shù)據(jù)后,想對(duì)數(shù)據(jù)進(jìn)行操作,但是可能有另外一個(gè)人對(duì)此做了操作,那再對(duì)此數(shù)據(jù)進(jìn)行操作就不對(duì)了。
此時(shí)需要明確加鎖來鎖住表,防止別人更改數(shù)據(jù),執(zhí)行結(jié)束后釋放鎖。
lock tables XX write;
XXXXXX;
unlock tables;
也可以使用相對(duì)更新代替絕對(duì)更新,相對(duì)于當(dāng)前值進(jìn)行更新,不根據(jù)上次的值算出一個(gè)絕對(duì)值進(jìn)行更新。這樣避免了多條語句的非原子操作。
set a = a - 3 XXXXXXXXXXX;
總結(jié)
以上是生活随笔為你收集整理的Mysql事务处理问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sublime :[Decode err
- 下一篇: Token令牌 Redis 案例