日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

Mysql对事务的支持

發(fā)布時(shí)間:2024/4/17 数据库 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Mysql对事务的支持 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

http://apps.hi.baidu.com/share/detail/31961419

?

MySQL與事務(wù)

歡迎訪問(wèn)火丁筆記:http://huoding.com/

火丁的訂閱地址:http://huoding.com/feed

作者:老王

MySQL5.X都已經(jīng)發(fā)布好久了,但是還有很多人認(rèn)為MySQL是不支持事務(wù)處理的,這不得不怪他們是孤陋寡聞的,其實(shí),只要你的MySQL版本支持BDB或InnoDB表類型,那么你的MySQL就具有事務(wù)處理的能力。這里面,又以InnoDB表類型用的最多,雖然后來(lái)發(fā)生了諸如Oracle收購(gòu)InnoDB等令MySQL不爽的事情,但那些商業(yè)上的斗爭(zhēng)與技術(shù)無(wú)關(guān),下面以InnoDB表類型為例簡(jiǎn)單說(shuō)一下MySQL中的事務(wù)。

先來(lái)明確一下事務(wù)涉及的相關(guān)知識(shí):

事務(wù)都應(yīng)該具備ACID特征。所謂ACID是Atomic(原子性),Consistent(一致性),Isolated(隔離性),Durable(持續(xù)性)四個(gè)詞的首字母所寫,下面以“銀行轉(zhuǎn)帳”為例來(lái)分別說(shuō)明一下它們的含義:

原子性:組成事務(wù)處理的語(yǔ)句形成了一個(gè)邏輯單元,不能只執(zhí)行其中的一部分。換句話說(shuō),事務(wù)是不可分割的最小單元。比如:銀行轉(zhuǎn)帳過(guò)程中,必須同時(shí)從一個(gè)帳戶減去轉(zhuǎn)帳金額,并加到另一個(gè)帳戶中,只改變一個(gè)帳戶是不合理的。

一致性:在事務(wù)處理執(zhí)行前后,數(shù)據(jù)庫(kù)是一致的。也就是說(shuō),事務(wù)應(yīng)該正確的轉(zhuǎn)換系統(tǒng)狀態(tài)。比如:銀行轉(zhuǎn)帳過(guò)程中,要么轉(zhuǎn)帳金額從一個(gè)帳戶轉(zhuǎn)入另一個(gè)帳戶,要么兩個(gè)帳戶都不變,沒(méi)有其他的情況。

隔離性:一個(gè)事務(wù)處理對(duì)另一個(gè)事務(wù)處理沒(méi)有影響。就是說(shuō)任何事務(wù)都不可能看到一個(gè)處在不完整狀態(tài)下的事務(wù)。比如說(shuō),銀行轉(zhuǎn)帳過(guò)程中,在轉(zhuǎn)帳事務(wù)沒(méi)有提交之前,另一個(gè)轉(zhuǎn)帳事務(wù)只能處于等待狀態(tài)。

持續(xù)性:事務(wù)處理的效果能夠被永久保存下來(lái)。反過(guò)來(lái)說(shuō),事務(wù)應(yīng)當(dāng)能夠承受所有的失敗,包括服務(wù)器、進(jìn)程、通信以及媒體失敗等等。比如:銀行轉(zhuǎn)帳過(guò)程中,轉(zhuǎn)帳后帳戶的狀態(tài)要能被保存下來(lái)。

再來(lái)看看哪些問(wèn)題會(huì)用到事務(wù)處理:

?

這里不說(shuō)“銀行轉(zhuǎn)帳”的例子了,說(shuō)一個(gè)大家實(shí)際更容易遇到的“網(wǎng)上購(gòu)書”的例子。先假設(shè)一下問(wèn)題的背景:網(wǎng)上購(gòu)書,某書(數(shù)據(jù)庫(kù)編號(hào)為123)只剩最后一本,而這個(gè)時(shí)候,兩個(gè)用戶對(duì)這本書幾乎同時(shí)發(fā)出了購(gòu)買請(qǐng)求,讓我們看看整個(gè)過(guò)程:

在具體分析之前,先來(lái)看看數(shù)據(jù)表的定義:

-------------------------------------------------------------------------------

create table?book
(
??? book_id unsigned int(10) not null auto_increment,
??? book_name varchar(100) not null,
??? book_price float(5, 2) not null, #我假設(shè)每本書的價(jià)格不會(huì)超過(guò)999.99元
??? book_number int(10) not null,
??? primary key (book_id)
)
type = innodb; #engine = innodb也行

-------------------------------------------------------------------------------

對(duì)于用戶甲來(lái)說(shuō),他的動(dòng)作稍微比乙快一點(diǎn)點(diǎn),其購(gòu)買過(guò)程所觸發(fā)的動(dòng)作大致是這樣的:

-------------------------------------------------------------------------------

1. SELECT?book_number FROM?book?WHERE??book_id = 123;

book_number大于零,確認(rèn)購(gòu)買行為并更新book_number

2. UPDATE book?SET book_number = book_number - 1 WHERE??book_id = 123;

購(gòu)書成功

-------------------------------------------------------------------------------

而對(duì)于用戶乙來(lái)說(shuō),他的動(dòng)作稍微比甲慢一點(diǎn)點(diǎn),其購(gòu)買過(guò)程所觸發(fā)的動(dòng)作和甲相同:

-------------------------------------------------------------------------------

1. SELECT?book_number FROM?book?WHERE??book_id = 123;

這個(gè)時(shí)候,甲剛剛進(jìn)行完第一步的操作,還沒(méi)來(lái)得及做第二步操作,所以book_number一定大于零

2. UPDATE book?SET book_number = book_number - 1 WHERE??book_id = 123;

購(gòu)書成功

-------------------------------------------------------------------------------

表面上看甲乙的操作都成功了,他們都買到了書,但是庫(kù)存只有一本,他們?cè)趺纯赡芏汲晒δ?#xff1f;再看看數(shù)據(jù)表里book_number的內(nèi)容,已經(jīng)變成“-1”了,這當(dāng)然是不能允許的(實(shí)際上,聲明這樣的列類型應(yīng)該加上unsigned的屬性,以保證其不能為負(fù),這里是為了說(shuō)明問(wèn)題所以沒(méi)有這樣設(shè)置)

好了,問(wèn)題陳述清楚了,再來(lái)看看怎么利用事務(wù)來(lái)解決這個(gè)問(wèn)題,打開(kāi)MySQL手冊(cè),可以看到想用事務(wù)來(lái)保護(hù)你的SQL正確執(zhí)行其實(shí)很簡(jiǎn)單,基本就是三個(gè)語(yǔ)句:開(kāi)始,提交,回滾。

-------------------------------------------------------------------------------

開(kāi)始:START TRANSACTION或BEGIN語(yǔ)句可以開(kāi)始一項(xiàng)新的事務(wù)

提交:COMMIT可以提交當(dāng)前事務(wù),是變更成為永久變更

回滾:ROLLBACK可以回滾當(dāng)前事務(wù),取消其變更

此外,SET AUTOCOMMIT = {0 | 1}可以禁用或啟用默認(rèn)的autocommit模式,用于當(dāng)前連接。

-------------------------------------------------------------------------------

那是不是只要用事務(wù)語(yǔ)句包一下我們的SQL語(yǔ)句就能保證正確了呢?比如下面代碼:

-------------------------------------------------------------------------------

BEGIN;

SELECT?book_number FROM?book?WHERE??book_id = 123;

// ...

UPDATE?book?SET book_number = book_number - 1 WHERE??book_id = 123;

COMMIT;

-------------------------------------------------------------------------------

答案是否定了,這樣依然不能避免問(wèn)題的發(fā)生,如果想避免這樣的情況,實(shí)際應(yīng)該如下:

-------------------------------------------------------------------------------

BEGIN;

SELECT?book_number FROM?book?WHERE??book_id = 123 FOR UPDATE;

// ...

UPDATE?book?SET book_number = book_number - 1 WHERE??book_id = 123;

COMMIT;

-------------------------------------------------------------------------------

由于加入了FOR UPDATE,所以會(huì)在此條記錄上加上一個(gè)行鎖,如果此事務(wù)沒(méi)有完全結(jié)束,那么其他的事務(wù)在使用SELECT ... FOR UPDATE請(qǐng)求的時(shí)候就會(huì)處于等待狀態(tài),直到上一個(gè)事務(wù)結(jié)束,它才能繼續(xù),從而避免了問(wèn)題的發(fā)生,需要注意的是,如果你其他的事務(wù)使用的是不帶FOR UPDATE的SELECT語(yǔ)句,將得不到這種保護(hù)。

最后看看PHP + MySQL事務(wù)操作的代碼演示:

實(shí)際LAMP應(yīng)用中,一般PHP使用AdoDB操作MySQL,下面給出AdoDB相應(yīng)的代碼方便大家查閱:

-------------------------------------------------------------------------------

<?php
//?...

$adodb->startTrans
();

//實(shí)際,getOne所調(diào)用的查詢也可以直接放到rowLock來(lái)進(jìn)行,這里只是為了演示效果能更明顯些。

$adodb->rowLock('book',?'book_id?=?123'
);

$bookNumber?=?$adodb->getOne("SELECT?book_number?FROM?book?WHERE??book_id?=?123"
);

$adodb->execute("UPDATE?book?SET?book_number?=?book_number?-?1?WHERE??book_id?=?123"
);

$adodb->completeTrans
();

//?...
?>

-------------------------------------------------------------------------------

其中,rowLock的方法就是調(diào)用的FOR UPDATE來(lái)實(shí)現(xiàn)的行鎖,你可能會(huì)想把“FOR UPDATE”直接寫到$adodb->getOne()調(diào)用的那條SQL語(yǔ)句里面去實(shí)現(xiàn)行鎖的功能,不錯(cuò),那樣確實(shí)可以,但是并不是所有的數(shù)據(jù)庫(kù)都使用“FOR UPDATE”語(yǔ)法來(lái)實(shí)現(xiàn)行鎖功能,比如Sybase使用“HOLDLOCK”的語(yǔ)法來(lái)實(shí)現(xiàn)行鎖功能,所以為了你的數(shù)據(jù)庫(kù)抽象層保持可移植性,我還是勸你用rowLock來(lái)實(shí)現(xiàn)行鎖功能,至于可移植性就交給AdoDB好了,嗯,有點(diǎn)扯遠(yuǎn)了,今兒就說(shuō)到這里了。

-------------------------------------------------------------------------------

附:

AdoDB中存在一個(gè)setTransactionMode()方法,能夠設(shè)置事務(wù)的隔離級(jí)別,如下:

SetTransactionMode allows you to pass in the transaction mode to use for all subsequent transactions for that connection session. Note: if you have persistent connections and using mysql or mssql, you might have to explicitly reset your transaction mode at the beginning of each page request. This is only supported in postgresql, mssql, mysql with InnoDB and oci8 currently. For example:

$db->SetTransactionMode("SERIALIZABLE");
$db->BeginTrans();
$db->Execute(...); $db->Execute(...);
$db->CommiTrans();

$db->SetTransactionMode(""); // restore to default
$db->StartTrans();
$db->Execute(...); $db->Execute(...);
$db->CompleteTrans();

Supported values to pass in:

??? * READ UNCOMMITTED (allows dirty reads, but fastest)
??? * READ COMMITTED (default postgres, mssql and oci8)
??? * REPEATABLE READ (default mysql)
??? * SERIALIZABLE (slowest and most restrictive)

You can also pass in database specific values such as 'SNAPSHOT' for mssql or 'READ ONLY' for oci8/postgres.

為了您的安全,請(qǐng)只打開(kāi)來(lái)源可靠的網(wǎng)址

打開(kāi)網(wǎng)站????取消

來(lái)自: http://hi.baidu.com/thinkinginlamp/blog/item/d677cffcb7098482b901a014.html

?

總結(jié)

以上是生活随笔為你收集整理的Mysql对事务的支持的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。