常常在專案中見到這樣的dml語句:
update table1 set column1=
2where id=
12345
12345
然後在程式中 var temp=total+
10 最後一步 update table1 set total=#temp# where id=
12345
解決方案:
update table1 set total=total+
10where id=
12345
這裡直接利用語句級的原子性,不用先查詢再做加法。
②悲觀鎖:利用for update行鎖(先查詢再更新)
同樣是上面的例子。
解決方案:
首先,開啟事務
select total from table1 where id=
12345
forupdate
然後在程式中 var temp=total+
10 之後更新
update table1 set total=#temp# where id=
12345
最後,關閉事務。
注意,這裡幾條基於一定要在事務中執行。
③樂觀鎖:更新時檢查版本標誌
新增乙個欄位version,每次update都要對這個version加1,更新的時候檢查這個version是否變化,如果已經變化了,表示被更新過了。
首先select total,version,id from table1 where id=
12345
假設這裡version=20,
然後在程式中
var temp=total+
10 之後更新
update table1 set total=#temp#,version=version+1 where id=
12345 and version=20
檢查更新語句的返回值是否等於1,如果不等於1表示更新不成功,根據實際業務情況,可以直接反饋給使用者,或者再做其他重試處理。
上面三種方法一般都有自己的使用場合:
①第一種方法,一般適合某個字段需要根據更新前的狀態動態增加或者減少等做出變化的情況,這類需求處理起來無往不利。
② 第二種方法適用於使用者更新一定要保證成功的情況,即更改及有效的情況,如果併發更新程式很高,一般採用這種方式比較妥當,可以減少更新失敗的情況。
③第三種方法,不需要對資料進行事先鎖定,更新只需要檢查版本標誌,即可知道是否已經被別人更新過了,適合於對更新成功要求不高的使用者,即可以通過簡單提示,然後讓使用者重新查詢再修改的情況。如果併發程度很高,這種方法失敗的機率也很高,所以一般不太適合。
當然,這些都要根據實際情況來決定,一般系統中會綜合運用上訴的幾種方法來解決問題。總之一句話,寫覆蓋的問題大家一定要引起重視,不然出現了問題,你也只能按靈異事件處理了,因為併發問題,有的資料怎麼來的都不知道。
早先我也曾提到過這裡的問題:《保持業務資料同步》
資料庫小心得
1 內連線 查詢出所有記錄都滿足條件。之前在mysql中多用的是方言,就是mysql特有的語句,如select from 表1 別名1,表2 別名2where別名1.xx 別名2.xx 關聯條件用來消除笛卡爾積 而這種語句的標準形 式 就是內連線。select from 表1 別名1 inner j...
練習寫資料庫
create database factorywork gouse factorywork gocreate table employee employeeid int not null primary key,employeename char 20 not null,employee char ...
資料庫不小心刪除恢復
資料庫不小心刪除或者表不小心刪除,通過mysql恢復的話需要確保刪除前是mysql是開啟binlog。具體步驟 1.查詢binlog狀態以及位置。在 etc my.cfg檢視binlog開啟狀態 cat etc my.cnf 可以看到binlog開始狀態是開啟的。2.mysql查詢執行的binlog...