樂觀鎖和悲觀鎖

樂觀鎖:數據庫

原理:
	1)經過在數據庫表中添加一個版本號(version)字段來實現樂觀鎖。
	2)更新前先獲取到該條數據的版本號(v1),而後在更新語句(更新數據&更新版本號)的where條件中添加 version=v1 條件,
		1>若知足version=v1條件(即:成功獲取樂觀鎖),則成功更新數據且版本號+1;
		2>若不知足version=v1條件(即:獲取樂觀鎖失敗),說明該條數據被其它線程修改過了,則更新失敗,回滾事務。
特色:
	1)不發生獲取鎖失敗的狀況下,開銷比較小。
	2)若獲取鎖失敗,則代碼須要回滾,開銷比較大。
	
應用:
	樂觀鎖適用於鎖獲取失敗的機率比較小的場景,即:讀取比較頻繁、寫入較少的場景。

缺點:
	只能保證本系統對數據(數據庫表)的操做是安全的,外部系統對數據(數據庫表)的操做是不可控的。
	解決辦法:對外部系統設置權限,即外部系統只有普通查詢的權限。

悲觀鎖:安全

原理:使用數據庫提供的鎖機制(select .. for update)。

注意:使用悲觀鎖前,必須先關閉MySQL的自動提交屬性。

應用:
	寫入比較頻繁的場景。

咱們應該儘可能避免使用長事務:session

1)在一個事務中執行批量操做(eg:循環插入數據、循環刪除數據等)會致使該事務的執行時間變長。
2)長事務會致使數據庫鏈接被長時間持有,若是該請求的併發量較高,則極可能出現鏈接池中的鏈接被用光的狀況,從而致使其它的請求(因沒法獲取到數據庫鏈接)一直處於等待狀態,沒法被響應。
3)咱們應該將事務的範圍控制在單個操做上。

Hibernate中的樂觀鎖和悲觀鎖:併發

概念:指數據庫的隔離級別設爲read committed時,爲了解決不可重複讀的問題而採用的兩種辦法:

1)設定hibernate的事務隔離級別(使用hibernate.connection.isolation配置:取值一、二、四、8)
	hibernate.connection.isolation = 2(若是不設,則默認依賴數據庫自己的級別)
2)採用樂觀鎖和悲觀鎖解決不可重複讀的問題
	1)悲觀鎖:使用另外一種load方法:load(xx.class , id , LockMode.Upgrade),把讀出來的數據加上一把鎖,在事務結束前別人沒法訪問,須要藉助數據庫中的鎖。
		注:LockMode.UPGRADE_NOWAIT是 ORACLE 支持的鎖的方式
	2)樂觀鎖:在程序中添加一個version字段,用來檢查是否被修改過。版本檢查使用版本號或者時間戳來檢測更新衝突(而且防止更新丟失)。
		在實體類中增長version屬性(數據庫也會對應生成該字段,初始值爲0),並在其get方法前加@Version註解,則在操做過程當中每更新一次該行數據則version值加1,便可在事務提交前判斷該數據是否被其餘事務修改過。

eg:
	悲觀鎖(PessimisticLock):

	public void testPessimisticLock() {
		Session session = sf.openSession();
		session.beginTransaction();
		
		// LockMode.UPGRADE 的意思就是:在讀這條記錄的時候,請數據庫爲我讀的這條記錄加把鎖
		Account a = (Account)session.load(Account.class, 1L, LockMode.UPGRADE);
		int balance = a.getBalance();
		//do some caculation
		balance = balance - 10;
		a.setBalance(balance);
		
		session.getTransaction().commit();
		session.close();
	}

	控制檯發出的SQL語句:select ... for update	
	分析:在select語句後加上了for update,說明這裏在數據庫中加了一把鎖。
相關文章
相關標籤/搜索