事務的併發問題:髒讀、不可重複讀、幻讀。
髒讀:一個事務讀取另外一個事務未提交的數據。
不可重複讀:在一個事務中,讀取到另外一個事務已經提交update數據,形成兩次讀取不同。
幻讀:在一個事務中,讀取到另外一個事務已經提交insert數據,形成讀取記錄條數不同。
丟失更新:兩個事務同時修改目標數據,後提交的事務,會覆蓋以前提交的數據。 java
鑑於併發訪問出現的以上問題,數據庫提供了事務隔離級別:
1. READ_UNCOMMITED:會發生以上全部問題
2. READ_COMMITTED:阻止髒讀的發生,會發生不可重複讀和幻讀(Oracle 默認級別)
3. REPEATABLE_READ:阻止髒讀和不可重複讀發生,會發生幻讀(MySQL 默認級別)
4. SERIALIZABLE:不會發生併發問題,串行初始化(性能很是差,也不會使用)
mysql
1)start transaction:開始事務
2)commit:提交事務
sql
<hibernate-configuration> <session-factory> <!-- 修改事務隔離級別 --> <property name="hibernate.connection.isolation">2</property>
隔離級別對應數值:
read uncommitted isolation --- 1
read committed isolation ------ 2
repeatable read isolation ------ 4
serializable isolation ----------- 8 數據庫
丟失更新問題解決:
悲觀鎖和樂觀鎖。 session
假設丟失更新發生機率很大,底層原理使用數據庫內部鎖的機制。 併發
1)Mysql數據庫內部提供讀鎖(共享鎖)、寫鎖(排它鎖 );
2)一張數據表容許添加多個讀鎖;
3)一張數據表只能添加一個寫鎖,其與其餘鎖互斥。添加了寫鎖則不能再添加讀鎖;
4)默認狀況下,在修改記錄時,會自動添加寫鎖;
5)在執行查詢時,也能夠爲數據添加共享鎖和排它鎖
select * from customer lock in share mode; 添加共享鎖
select * from customer for update; 添加排它鎖
6)悲觀鎖使用的便是排它鎖。第1個修改執行select * from customer for update,第個操做(包括查詢)須要等待
session提供.get(Class class, Serializable id, LockMode lockMode);
oracle
//類型,OID,鎖 PojoUser user = (PojoUser) session.get(PojoUser.class, 1, LockMode.UPGRADE); //更新操做 user.setName("XXxxx");mysql 對應 LockMode UPGRADE ;
假設丟失更新發生機率不高,底層原理爲數據添加版本號,由程序來維護版本。 app
提交的版本號和數據庫中版本不一樣則報錯: dom
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [cn.cvu.hibernate.domain.PojoUser#3]
- end
性能