有關事務(小總結)
事務的屬性:
* propagation : 事務傳播行為
* isolation : 事務隔離級別
* read-only : 事務是否只讀
* rollback-for : 發生哪些異常回滾 , 等同于 -Exception
* no-rollback-for : 發生哪些異常 仍然提交 ,等同于 +Exception
多個事務并發是存在的問題:
1 臟讀:讀未提交
就是第一個事務查詢到了第二個事務還沒有提交的數據,這時候第二個事務可能會反悔,撤銷動作
2 不可重復讀:讀已提交
就是第一個事務在某一時間查詢某條記錄,第二時間又查詢,原來的數據已經更新(第二個事務的更新提交后的數據),他不能判斷哪個數據才是正確的,也不能保證還有沒有人去改
3 幻讀:讀已提交
就是第一個事務在某一時間查詢某條記錄,第二時間又查詢,發現多了一條數據(第二個事務的insert提交后的數據)
4 丟失更新:
兩個事務操作相同的數據時,后提交的事務覆蓋之前提交的事務
隔離級別:
READ_UNCOMMITED 允許你讀取還未提交的改變了的數據。可能導致臟、幻、不可重復讀
READ_COMMITTED 允許在并發事務已經提交后讀取。可防止臟讀,但幻讀和 不可重復讀仍可發生
REPEATABLE_READ 對相同字段的多次讀取是一致的,除非數據被事務本身改變。可防止臟、不可重復讀,但幻讀仍可能發生。
SERIALIZABLE 完全服從ACID的隔離級別,確保不發生臟、幻、不可重復讀。這在所有的隔離級別中是最慢的,它是典型的通過完全鎖定在事務中涉及的數據表來完成的。
丟失更新問題解決: 悲觀鎖 和 樂觀鎖
1) 悲觀鎖 : 假設丟失更新發生概率很大, 底層原理使用數據庫內部 鎖的機制
* mysql為例,數據庫內部提供 讀鎖(共享鎖) 、寫鎖(排它鎖 )
* 允許一張數據表 添加多個讀鎖
* 一張數據表 只能添加 一個寫鎖(排它鎖),與其他鎖 互斥 ,添加排它鎖 也不能添加共享鎖
* 默認情況下,在修改記錄時,會自動添加 寫鎖
在執行查詢時,也可以為數據添加 共享鎖和排它鎖
select * from customer lock in share mode ; 添加共享鎖
select * from customer for update; 添加排它鎖
悲觀鎖 使用排它鎖 第一個管理員修改時 select * from customer for update 第二個管理員 用同樣查詢需要等待
Hibernate查詢時 Session 提供 Object get(Class clazz, Serializable id, LockMode lockMode)
mysql : LockMode UPGRADE
oracle : LockMode UPGRADE_NOWAIT
Customer customer = (Customer) session.get(Customer.class, 1 ,LockMode.UPGRADE);
2) 樂觀鎖 : 假設丟失更新發生概率不高, 底層原理為數據添加 版本號 , 由程序來維護版本
在Customer類中 添加 Integer version 代表 版本字段
在Customer.hbm.xml 中添加版本字段
<!-- name 就是 Customer 類中 版本字段 屬性名 -->
<version name="version"></version>
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [cn.itcast.domain.Customer#3]
事務的傳播行為(Progation)(種):
常用 : PROPAGATION_REQUIRED(默認行為) 、PROPAGATION_REQUIRES_NEW 、PROPAGATION_NESTED
PROPAGATION_REQUIRED(默認行為) : 取款和打印憑條在同一個事務中 ,打印憑條成功,取款成功 ; 打印憑條失敗 取款失敗
PROPAGATION_REQUIRES_NEW : 取款和打印憑條一定不在一個事務中 ,無論打印憑條是否成功,和取款沒關系
PROPAGATION_NESTED : 原理基于JDBC3.0 提供SavePoint ,打印憑條如果失敗了, 程序是可以控制 取款操作是提交還是回滾 , 取款后,打印憑條前,savePoint , 打印憑條失敗, 回滾到SavePoint