2.數據庫之事務管理
阿新 • • 發佈:2018-03-07
數據庫 並發控制 事務
1.3 並發控制
不論何時,只要有多個連接在同一時刻修改數據,就會產生並發問題。但是當多個連接只做讀取數據操作時,不會產生並發控制的問題,因為讀取操作不會修改數據。
在事務執行過程中,只有執行commit或者rollback後,鎖才會被釋放,而且是該事務內所有表的鎖同步釋放。
1.3.1 讀寫鎖
對於並發問題的解決方案就是並發控制。並發控制是由鎖系統來完成的,鎖系統包含兩種鎖,共享鎖和排他鎖,也叫讀鎖和寫鎖。讀鎖是共享的,相互不堵塞,也就是說在同一時刻多個連接可以讀取同一資源而不相互幹擾。寫鎖是拍他的,也就是說一個寫鎖會阻塞其他的讀鎖和寫鎖。
1.3.2 鎖粒度
提高共享資源並發性的方式就是讓鎖定對象更有選擇性。盡量只鎖定需要修改的部分而不是所有數據。這樣不會影響到其他線程對未鎖定數據的讀取和寫操作。
問題是加鎖也需要消耗資源。包括鎖的各項操作,比如加鎖、釋放鎖、檢查鎖是否解除,都會加大系統的開銷。如果花費部分性能去管理鎖而不是讀取數據,也會影響到系統的性能。這就涉及到鎖策略。所謂的鎖策略就是在系統性能和數據安全性之間尋求平衡。mysql的每種存儲引擎都有自己的鎖策略。
最重要的兩種鎖策略:表鎖和行級鎖。
表鎖:表鎖會鎖定整張表,是對系統開銷最小的鎖策略。當一個線程對表進行寫操作時,整張表被鎖定,這會阻塞其他的線程對該表的讀寫操作。盡管存儲引擎層可以管理鎖,mysql服務層也會使用有效的表鎖實現不同的目的。例如服務器層會為諸如alter table之類加表鎖,忽略存儲引擎層的鎖機制。
行級鎖:行級鎖可以最大程度的支持並發處理(同時也帶來了最大的鎖開銷)。行級鎖只在存儲引擎層實現。
在實際的數據庫系統中,每時每刻都在發生鎖定,當某個用戶正在修改某一部分數據時,mysql會通過鎖定防止其他用戶讀取同一數據。
1.4 事務
1.4.1 事務的特性:原子性、隔離性、持久性
原子性:整個事務中的所有操作要麽全部成功,要麽全部失敗,對於一個事務來說,不可能只執行其中的一部分。
隔離性:一個事務所做的修改在提交之前,其他的事務是不可見的。
持久性:一旦事務提交,所做的修改就會永久保存到數據庫中。
1.4.2 事務的隔離級別:
1. 讀未提交:一個事務可以讀取另一個事務未提交的數據。這樣會產生臟讀,實際生產環境一般不會用。
2. 讀提交/(另一個事務執行update操作時本事務不可重復讀):一個事務A有兩個相同的sql查詢語句,這個事務開啟第一個查詢語句時,另一個事務B開始對這條數據執行更新(update)操作,那麽事務B會對這條記錄開啟行級鎖,此時事務A就會被阻塞,第二條查詢的sql語句要在事務B執行完後才能執行,而此時事務A的第二次查詢結果跟第一次查詢結果就不一樣了。這就是不可重復讀。讀提交可以解決臟讀的問題。大部分的數據庫默認采用讀提交的事務隔離級別,但mysql不是。
3. 可重復讀(解決了不可重復讀的問題,但是在另一個事務執行insert操作時,會出現幻讀):事務A開始讀取數據時,其他的事務不允許進行修改(update)操作。mysql默認采用重復讀的隔離級別。但是重復讀可能會出現幻讀,因為重復讀針對的是update操作。如果事務A要預覽用戶的消費清單並打印清單,預覽時,用戶有10條消費記錄,而在打印清單之前,用戶又消費了一筆,事務B執行了添加操作並提交了事務,此時事務A打印的清單會發現多了一條記錄,這就是幻讀。
4. 串行執行事務。
mysql默認的事務隔離級別是可重復讀,當然可以修改mysql默認的事務隔離級別。
1.4.3 死鎖
死鎖是指兩個或多個事務已經鎖定了某個資源,並互相請求去鎖定對方已經鎖定的資源,這樣會造成多個事務無法釋放鎖導致惡性循環。這樣每個事務都不會執行完並一直占有鎖。
例如:
事務1:
start transaction;
update student set name = ‘zhangsan‘ where id = 1;
update student set name = ‘lisi‘ where id = 2;
commit;
事務2:
start transaction;
update student set name = ‘zhangsan‘ where id = 2;
update student set name = ‘lisi‘ where id = 1;
commit;
如果湊巧,兩個事務都執行了第一條sql,更新了一條數據,也就是鎖定了改行數據。接著每個事務都嘗試執行第二條sql,卻發現該行已被對方鎖定。然後兩個事務都等待對方釋放鎖,同時又擁有對方需要的鎖,陷入死循環。除非有外部因素介入才能解除死鎖。
1.4.4 mysql中的事務
mysql的事務默認采用autocommit模式。也就是說只要不顯式的開啟一個事務,每一條sql都會被當做當做一個事務執行提交操作。在當前jdbc連接中,可以通過設置autocommit變量來啟用或禁用自動提交模式。
1.4.5 在事務中混合使用存儲引擎
mysql服務器層不管理事務,事務由下層的存儲引擎實現。所以在同一個事務中,使用多種存儲引擎是不可靠的。
如果在事務中操作了事務型的表和非事務型的表,在正常提交事務時不會出現問題。但是如果事務回滾,事務型的表數據會回滾,而非事務型的表則不會回滾,因為非事務型的表不支持事務,這樣就會導致數據紊亂。所以,為每張表選擇合適的存儲引擎非常重要。
mysql是自動提交事務的,使用jdbc時,只要不顯式的關閉自動提交,每一條sql都是一個事務。所以最好去創建一個事務,把下面的
所有操作放到一個事務裏,要不都成功,要不都失敗。
2.數據庫之事務管理