事務的核心是鎖和併發,採用同步控制的方式保證併發的狀況下性能儘量高,且容易理解。mysql
1、事務有四個基本特性:redis
一、原子性(atomicity):數據庫操做的最小基本單位,事務內的操做要麼都成功,要麼都失敗,中途不能被打斷。sql
二、一致性(consistency):事務執行後數據從一種狀態變成另一種狀態,不會存在事務的一部分數據寫入了數據庫,一部分沒有寫入。數據庫
三、隔離性(isolation):事務之間獨立執行,不相互干擾。併發
四、持久性(durability):事務一旦提交,對數據庫的修改是永久性的,不會改變。mvc
二、事務隔離oracle
當多個線程同時執行讀、算、寫操做時,若是不加訪問控制,系統勢必會產生衝突,舉例說明:高併發
併發的時候,事務不斷執行,這段時間簡稱T。T上有不少時間點,T0,T1,T2,T3,T4,T5..........T0爲時間起點,數據庫上有一個表user,字段name,point。性能
事務A:select name,point from user where id =1;優化
事務B:update user set point=point+1 where id =1;
髒讀:首先事務B開始執行,在T1的時候事務A又開始執行,這個時候B事務並無提交,事務A查詢的值是事務B未提交的值,若是此時B事務回滾,會形成事務A查詢到錯誤數據。這就是髒讀。
不可重讀:因而事務B修改point值的時候加鎖,事務A只能在B事務提交後才能查詢到結果,這樣防止了髒讀。可是若是事務A有兩次相同的查詢,分別在時間T0和T2,而再T1的時候事務B提交就會形成事務A兩次相同查詢的結果不同。這就是所謂的不可重讀。
幻讀:爲了防止出現重讀,則須要在事務A查詢的時候加讀鎖,在事務A提交以前,查詢的數據不會被修改。出克髒讀和不可重讀,還會出現幻讀的狀況。出現幻讀的狀況也是一個事務內兩次相同的查詢結果不同,和不可重讀不同的是,不可重讀第二次查詢的結果被修改或刪除,而幻讀第二次會查出新增的記錄,多是其餘事務插入了知足條件的記錄。而解決幻讀的問題會複雜不少,須要對第一次查詢的查詢條件的一段範圍加鎖,具體就不細說了。
爲了防止以上的狀況發生,事務隔離產生了:
Read Uncommitted:這個隔離級別最低,會出現髒讀、不可重讀和幻讀。這種隔離級別很危險,通常不用。
Read Committed:這個隔離級別稍微高一些,不會出現髒讀,但會出現不可重讀和幻讀,oracle默認使用的事務隔離級別。
Repeatable Read:不會出現髒讀和不可重讀,會出現幻讀。mysql默認的事務隔離級別。
Serializable:不會出現髒讀、不可重讀和幻讀。由於串行化隔離須要很大的系統消耗,併發很差,通常不會使用。
而mysql用了一個併發版本控制機制mvcc,爲了提升數據庫併發量,容許事務並行讀取寫入數據,這個時候若是咱們須要嚴格控制併發,就要加鎖。
三、處理事務經常使用方法
處理事務經常使用方法有排隊法、排他鎖、讀鎖、讀寫鎖、mvcc.
一、排隊法
最簡單也是最重要的事務處理方法,用單一線程處理數據,避免了併發帶來的同步問題。如redis,數據所有在內存中,則單線程處理全部Put、Get操做效率最高。
二、排他鎖
能夠利用排他鎖的方式來快速隔離併發讀寫事務。一個事務得到鎖後,其餘事務的讀寫操做block住。
三、讀寫鎖
若是是一系列讀事務,不會對數據進行修改,那這些事務是能夠並行的,所以一種針對讀讀場景的優化天然而然產生——讀寫鎖。讀寫鎖的核心是在屢次讀的操做中,同時容許多個讀者來訪問共享資源,提升併發性。
四、mvcc
本質是Copy On Write,也就是每次寫都是以從新開始一個新的版本的方式寫入數據,所以,數據庫中也就包含了以前的全部版本。在數據讀的過程當中,先申請一個版本號,若是該版本號小於正在寫入的版本號,則數據必定能夠查詢到,無需等到新版本徹底寫完便可返回查詢結果。這種方式能夠在讀讀不阻塞的前提下,實現讀寫/寫讀不阻塞,儘量保證全部的讀操做並行,而寫操做串行。
寫寫是無法優化的,必須串行。
四、調優
事務的調優的思路是在不影響業務應用的前提下:
第一,儘量減小鎖的覆蓋範圍,例如Myisam表鎖到Innodb的行鎖就是一個減小鎖覆蓋範圍的過程;對於原位鎖(排他鎖、讀寫鎖等)可變爲MVCC多版本(本質仍然是減小鎖的範圍)。
第二,增長鎖上可並行的線程數,例如讀鎖和寫鎖的分離,容許並行讀取數據。
第三,選擇正確鎖類型,其中悲觀鎖適合併發爭搶比較嚴重的場景;樂觀鎖適合併發爭搶不太嚴重的場景。