php與mysq事務處理整理

2021-06-20 22:05:44 字數 3426 閱讀 5227

事務都應該具備acid特徵。所謂acid是atomic(原子性),consistent(一致性),isolated(隔離性),durable(持續性)四個詞的首字母所寫,下面以「銀行轉帳」為例來分別說明一下它們的含義:

原子性:組成事務處理的語句形成了乙個邏輯單元,不能只執行其中的一部分。換句話說,事務是不可分割的最小單元。比如:銀行轉帳過程中,必須同時從乙個帳戶減去轉帳金額,並加到另乙個帳戶中,只改變乙個帳戶是不合理的。

一致性:在事務處理執行前後,資料庫是一致的。也就是說,事務應該正確的轉換系統狀態。比如:銀行轉帳過程中,要麼轉帳金額從乙個帳戶轉入另乙個帳戶,要麼兩個帳戶都不變,沒有其他的情況。

隔離性:乙個事務處理對另乙個事務處理沒有影響。就是說任何事務都不可能看到乙個處在不完整狀態下的事務。比如說,銀行轉帳過程中,在轉帳事務沒有提交之前,另乙個轉帳事務只能處於等待狀態。

持續性:事務處理的效果能夠被永久儲存下來。反過來說,事務應當能夠承受所有的失敗,包括伺服器、程序、通訊以及**失敗等等。比如:銀行轉帳過程中,轉帳後帳戶的狀態要能被儲存下來。

再來看看哪些問題會用到事務處理:

這裡不說「銀行轉帳」的例子了,說乙個大家實際更容易遇到的「網上購書」的例子。先假設一下問題的背景:網上購書,某書(資料庫編號為123)只剩最後一本,而這個時候,兩個使用者對這本書幾乎同時發出了購買請求,讓我們看看整個過程:

在具體分析之前,先來看看資料表的定義:

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, #我假設每本書的**不會超過999.99元

book_number int(10) not null,

primary key (book_id)

)type = innodb; #engine = innodb也行

對於使用者甲來說,他的動作稍微比乙快一點點,其購買過程所觸發的動作大致是這樣的:

1. select book_number from book where  book_id = 123;

book_number大於零,確認購買行為並更新book_number

2. update book set book_number = book_number - 1 where  book_id = 123;

購書成功

而對於使用者乙來說,他的動作稍微比甲慢一點點,其購買過程所觸發的動作和甲相同:

1. select book_number from book where  book_id = 123;

這個時候,甲剛剛進行完第一步的操作,還沒來得及做第二步操作,所以book_number一定大於零

2. update book set book_number = book_number - 1 where  book_id = 123;

購書成功

表面上看甲乙的操作都成功了,他們都買到了書,但是庫存只有一本,他們怎麼可能都成功呢?再看看資料表裡book_number的內容,已經變成 「-1」了,這當然是不能允許的(實際上,宣告這樣的列型別應該加上unsigned的屬性,以保證其不能為負,這裡是為了說明問題所以沒有這樣設定)

好了,問題陳述清楚了,再來看看怎麼利用事務來解決這個問題,開啟mysql手冊,可以看到想用事務來保護你的sql正確執行其實很簡單,基本就是三個語句:開始,提交,回滾。

開始:start transaction或begin語句可以開始一項新的事務

提交:commit可以提交當前事務,是變更成為永久變更

回滾:rollback可以回滾當前事務,取消其變更

此外,set autocommit = 可以禁用或啟用預設的autocommit模式,用於當前連線。

那是不是只要用事務語句包一下我們的sql語句就能保證正確了呢?比如下面**:

begin;

select book_number from book where  book_id = 123;

update book set book_number = book_number - 1 where  book_id = 123;

commit;

答案是否定了,這樣依然不能避免問題的發生,如果想避免這樣的情況,實際應該如下:

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,所以會在此條記錄上加上乙個行鎖,如果此事務沒有完全結束,那麼其他的事務在使用select ... for update請求的時候就會處於等待狀態,直到上乙個事務結束,它才能繼續,從而避免了問題的發生,需要注意的是,如果你其他的事務使用的是不帶for update的select語句,將得不到這種保護。

學習參考如下

由於innodb預設是row-level lock,所以只有「明確」的指定主鍵,mysql才會執行row lock (只鎖住被選取的資料例) ,否則mysql將會執行table lock (將整個資料表單給鎖住)。

舉個例子:

假設有個表單products ,裡面有id跟name二個字段,id是主鍵。

例1: (明確指定主鍵,並且有此筆資料,row lock)

select * from products where id='3' for update;

例2: (明確指定主鍵,若查無此筆資料,無lock)

select * from products where id='-1' for update;

例2: (無主鍵,table lock)

select * from products where name='mouse' for update;

例3: (主鍵不明確,table lock)

select * from products where id<>'3' for update;

例4: (主鍵不明確,table lock)

select * from products where id like '3' for update;

注1: for update僅適用於innodb,且必須在交易區塊(begin/commit)中才能生效。

注2: 要測試鎖定的狀況,可以利用mysql的command mode ,開二個視窗來做測試。

關於yii的事務處理

$transaction->commit();//提交事務

$transaction->rollback();//回滾事務

// 以下例項將需要事務處理的操作放進try裡

try catch (exception $e)

PHP 事務處理

在對資料庫會進行多次操作的時候會使用到事務 transaction 其中的底層邏輯如下 1 開啟事務 begin 2 取消資料庫自動寫入 set autocommit 0 3 sql1賦值 第一句所要執行的內容 4 sql2賦值 等等 5 執行mysql query sql1 sqln 6 判斷sq...

PHP與MYSQL事務處理

mysql的事務處理主要有兩種方法。1 用begin,rollback,commit來實現 begin 開始乙個事務 rollback 事務回滾 commit 事務確認 2 直接用set來改變mysql的自動提交模式 mysql預設是自動提交的,也就是你提交乙個query,它就直接執行!我們可以通過...

PHP與MYSQL事務處理

mysql的事務處理主要有兩種方法。1 用begin,rollback,commit來實現 begin 開始乙個事務 rollback 事務回滾 commit 事務確認 2 直接用set來改變mysql的自動提交模式 conn mysql connect localhost root root or...