mysql 使用select ... for update 做事務寫入前的確認
以mysql 的innodb 為例,預設的tansaction isolation level 為repeatable read,在select 的讀取鎖定主要分為兩種方式:
select ... lock in share modeselect ... for update
這兩種方式在事務(transaction) 進行當中select 到同乙個資料表時,都必須等待其它事務資料被提交(commit)後才會執行。而主要的不同在於lock in share mode 在有一方事務要update 同乙個表單時很容易造成死鎖 。
簡單的說,如果select 後面若要update 同乙個表單,最好使用select ... update。
舉個例子: 假設商品表單products 內有乙個存放商品數量的quantity ,在訂單成立之前必須先確定quantity 商品數量是否足夠(quantity>0) ,然後才把數量更新為1。
不安全的做法:
select quantity from products where id=3;update products set quantity = 1 where id=3;
為什麼不安全呢?
少量的狀況下或許不會有問題,但是大量的資料訪問「鐵定」會出問題。
如果我們需要在quantity>0 的情況下才能扣庫存,假設程式在第一行select 讀到的quantity 是2 ,看起來數字沒有錯,但是當mysql 正準備要update 的時候,可能已經有人把庫存扣成0 了,但是程式卻渾然不知,將錯就錯的update 下去了。
因此必須透過的事務機制來確保讀取及提交的資料都是正確的。
於是我們在mysql 就可以這樣測試: (注1)
set autocommit=0;begin work;select quantity from products where id=3 for update;****************************************===此時products 資料中id=3 的資料被鎖住(注3),其它事務必須等待此次事務提交後才能執行select * from products where id=3 for update (注2)如此可以確保quantity 在別的事務讀到的數字是正確的。****************************************===update products set quantity = '1' where id=3 ;commit work;****************************************===提交(commit)寫入資料庫,products 解鎖。
注1: begin/commit 為事務的起始及結束點,可使用二個以上的mysql command 視窗來互動觀察鎖定的狀況。
注2: 在事務進行當中,只有select ... for update 或lock in share mode 同一筆資料時會等待其它事務結束後才執行,一般select ... 則不受此影響。
注3: 由於innodb 預設為row-level lock,資料列的鎖定可參考這篇。
注4: innodb 表單盡量不要使用lock tables 指令,若情非得已要使用,請先看官方對於innodb 使用lock tables 的說明,以免造成系統經常發生死鎖。
mysql select ... for update 的row lock 與table lock
上面介紹過select ... for update 的用法,不過鎖定(lock)的資料是判別就得要注意一下了。由於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 ,開二個視窗來做測試。
以上內容來自:
安裝mysql出來警告怎麼辦 安裝mysql
最主要的乙個問題是mysql 5.7以上 與 mysql5.6以下的版本在安裝時大相徑庭,5.6以下版本一般都會提供預設配置檔案,5.7以上就不會,比如data資料夾,tmp資料夾等等。並且兩者在初始化時的 命令也不一樣,如果在5.7以上使用5.6以下的初始化命令,系統會發出警告並提示你該用哪個新的...
mysql 怎麼辦 mysql 密碼忘記怎麼辦
一 若資料庫是初次登陸 linux系統給資料庫生成了乙個原始密碼在檔案 var log mysqld.log中 grep temporary password var log mysqld.log 找到原始密碼 登陸 mysql uroot p 你找到的密碼 mysql set global val...
mysql不能建立表怎麼辦 MYSQL 不能建立表
can t create table ticket user role.frm errno 121 語法是對的,但顯示上面的錯誤 原因有三種 1 表名重複 2 以該名字命名的表之前建立過後來刪除了,但是對應的.frm檔案還留在磁碟上 3 主鍵名字在全資料庫範圍內不是唯一的 我出現的時候是第三個 ke...