事务与锁机制
2019獨角獸企業重金招聘Python工程師標準>>>
事務定義:
訪問并可能更新數據庫:一句或一組SQL,或者是一段程序,反正update了就是事務
ACID的4原則:
原子性:
一致性:
隔離性:不被干擾
持久性:永久改變
COMMIT:提交所有操作
ROLLBACK:回滾(撤銷)
表的類型:
MYSQL 的INNODB和BDB表支持事務,但MyISAM(默認)不支持事務
多事務可能的問題:
第一類丟失更新:撤銷一個事務,影響已提交事務
臟讀:讀到別的事務未提交的數據,而那個事務恰巧回滾了……
虛讀(幻讀):讀到別的事務新插入的數據
不可重復讀:讀到別的事務更新的數據,結果兩次讀取的數據不一樣了。
第二類丟失更新:覆蓋別的事務更新的數據
隔離級別:
Serializable(串行化):事務全看不到其他事務的更新,就是一個事務接著一個事務,沒啥并發性可言。當然它是隔離最高的了!
Repeatable Read(可重復讀):讀寫都會阻塞,所以事務間讀和寫互相看不到,但能看到其他事務新插入的記錄,解決不了虛讀問題。
Read Commited(讀已提交數據):寫的時候阻塞寫和讀,讀的時候不阻塞寫。結果事務看到其他事務新插入記錄和更新
Read Uncomitted(讀未提交數據):事務看到其他事務未提交的插入記錄和更新。也就是說隔離最弱,沒啥解決能力。
當然Read Commited用的最多,因為它安全、并發也好。但為了避免錯誤的讀寫,還需要用到樂觀鎖或者悲觀鎖。
悲觀鎖:其他事務會同時訪問資源,就是上鎖。它是數據庫的鎖機制,不是程序模塊實現的,因為可能多個系統在動數據庫嘛。
select?*?from?person?for?update?? update?person?set?name='ff'?where?id='1'非得提交了之后鎖才能釋放。所以第一句只要不執行完,其他的事務休想動符合條件的記錄。
在hibernate里實現悲觀鎖:
String?hqlStr?="from?TUser?as?user?where?user.name='Erica'"; Query?query?=?session.createQuery(hqlStr); query.setLockMode("user",LockMode.UPGRADE);?//?加鎖? List?userList?=?query.list();//?執行查詢,獲取數據類名是TUser 字段是user,原理上還是數據庫的 for update 子句
樂觀鎖:訪問時其他事務修改的概率很低,大不了重讀一次。完全靠隔離級別,。如果一次操作開銷很大,建議用悲觀鎖。數據庫里用版本號實現,說白了就是有個version字段嘛
比如:
select?*??from?person??? select?*??from?person?? update?person?set?name='xiaoming',version=version+1?where?id='1'?and?version=0;找不到版本號就重新來唄!這就避免了第二類丟失和不可重復讀。
舉個例子,比如AB都在修改賬戶里的錢,版本號0,當前100¥。A讀了100,扣了20,交上去就是80,版本號1;B如果沒同時讀,版本號改完就是2,也就沒問題了。如果真和A同時讀的,也讀了個100¥,那它修改后的版本號就是1,不大于當前版本號,所以不能更新,只好重新操作一遍咯!這個不難理解吧?
當然樂觀鎖也會出點小麻煩,因為它是程序實現的,不是數據庫實現的,所以臟讀是沒法避免的。比如這個系統回滾了,別的系統可不知道!
在hibernate里實現
<hibernate-mapping> <class name="org.hibernate.sample.TUser" table="t_user" dynamic-update="true" dynamic-insert="true" optimistic-lock="version" > …… </class> </hibernate-mapping>例子選自http://www.blogjava.net/loocky/archive/2006/11/15/81138.html
這樣對象TUser寫入關系型數據庫用的就是樂觀鎖了。optimistic-lock="version"表示用版本號控制。
相互學習,歡迎補充
轉載于:https://my.oschina.net/tdONEmadao/blog/214412
總結
- 上一篇: 梦到自己捡鸡蛋鸭蛋是什么意思
- 下一篇: Erlang并发机制 –进程调度