㈠ 資料庫的事務隔離級別,以及怎麼解決這些問題
sql標準定義了四種隔離級別:
目前mysql默認使用可重復讀隔離級別.
㈡ 事務隔離級別有哪些
事務的隔離級別有4種,由低到高分別為Read uncommitted 、Read committed 、Repeatable read 、Serializable 。事物的並發操作中可能休閑臟讀,不可重復讀,幻讀。
1、第一種隔離級別:Read uncommitted(讀未提交)
如果一個事務已經開始寫數據,則另外一個事務不允許同時進行寫操作,但允許其他事務讀此行數據,該隔離級別可以通過「排他寫鎖」,但是不排斥讀線程實現。這樣就避免了更新丟失,卻可能出現臟讀,也就是說事務B讀取到了事務A未提交的數據。
解決了更新丟失,但還是可能會出現臟讀。
2、第二種隔離級別:Read committed(讀提交)
如果是一個讀事務(線程),則允許其他事務讀寫,如果是寫事務將會禁止其他事務訪問該行數據,該隔離級別避免了臟讀,但是可能出現不可重復讀。事務A事先讀取了數據,事務B緊接著更新了數據,並提交了事務,而事務A再次讀取該數據時,數據已經發生了改變。
解決了更新丟失和臟讀問題。
3、第三種隔離級別:Repeatable read(可重復讀取)
可重復讀取是指在一個事務內,多次讀同一個數據,在這個事務還沒結束時,其他事務不能訪問該數據,這樣就可以在同一個事務內兩次讀到的數據是一樣的,因此稱為是可重復讀隔離級別,讀取數據的事務將會禁止寫事務,寫事務則禁止任何其他事務,這樣避免了不可重復讀和臟讀,但是有時可能會出現幻讀。
讀取數據的事務可以通過「共享讀鏡」和「排他寫鎖」實現。
解決了更新丟失、臟讀、不可重復讀、但是還會出現幻讀。
4、第四種隔離級別:Serializable(可序化)
提供嚴格的事務隔離,它要求事務序列化執行,事務只能一個接著一個地執行,但不能並發執行,如果僅僅通過「行級鎖」是無法實現序列化的,必須通過其他機制保證新插入的數據不會被執行查詢操作的事務訪問到。
序列化是最高的事務隔離級別,同時代價也是最高的,性能很低,一般很少使用,在該級別下,事務順序執行,不僅可以避免臟讀、不可重復讀,還避免了幻讀。
事務的基本要素(ACID)
1、原子性(Atomicity):事務開始後所有操作,要麼全部做完,要麼全部不做,不可能停滯在中間環節。事務執行過程中出錯,會回滾到事務開始前的狀態,所有的操作就像沒有發生一樣。也就是說事務是一個不可分割的整體,就像化學中學過的原子,是物質構成的基本單位。
2、一致性(Consistency):事務開始前和結束後,資料庫的完整性約束沒有被破壞 。比如A向B轉賬,不可能A扣了錢,B卻沒收到。
3、隔離性(Isolation):同一時間,只允許一個事務請求同一數據,不同的事務之間彼此沒有任何干擾。比如A正在從一張銀行卡中取錢,在A取錢的過程結束前,B不能向這張卡轉賬。
4、持久性(Durability):事務完成後,事務對資料庫的所有更新將被保存到資料庫,不能回滾。
以上內容參考:事務隔離級別 - 網路
㈢ 事務的隔離級別是什麼
資料庫事務的隔離級別有4種,由低到高分別為Read uncommitted 、Read committed 、Repeatable read 、Serializable 。而且,在事務的並發操作中可能會出現臟讀,不可重復讀,幻讀。
1、Read uncommitted
讀未提交,顧名思義,就是一個事務可以讀取另一個未提交事務的數據。
2、Read committed
讀提交,顧名思義,就是一個事務要等另一個事務提交後才能讀取數據。
3、Repeatable read
重復讀,就是在開始讀取數據(事務開啟)時,不再允許修改操作。
4、Serializable 序列化
Serializable 是最高的事務隔離級別,在該級別下,事務串列化順序執行,可以避免臟讀、不可重復讀與幻讀。但是這種事務隔離級別效率低下,比較耗資料庫性能,一般不使用。
㈣ 如何處理資料庫並發問題
想要知道如何處理數據並發,自然需要先了解數據並發。
什麼是數據並發操作呢?
就是同一時間內,不同的線程同時對一條數據進行讀寫操作。
在互聯網時代,一個系統常常有很多人在使用,因此就可能出現高並發的現象,也就是不同的用戶同時對一條數據進行操作,如果沒有有效的處理,自然就會出現數據的異常。而最常見的一種數據並發的場景就是電商中的秒殺,成千上萬個用戶對在極端的時間內,搶購一個商品。針對這種場景,商品的庫存就是一個需要控制的數據,而多個用戶對在同一時間對庫存進行重寫,一個不小心就可能出現超賣的情況。
針對這種情況,我們如何有效的處理數據並發呢?
第一種方案、資料庫鎖
從鎖的基本屬性來說,可以分為兩種:一種是共享鎖(S),一種是排它鎖(X)。在MySQL的資料庫中,是有四種隔離級別的,會在讀寫的時候,自動的使用這兩種鎖,防止數據出現混亂。
這四種隔離級別分別是:
讀未提交(Read Uncommitted)
讀提交(Read Committed)
可重復讀(Repeated Read)
串列化(Serializable)
當然,不同的隔離級別,效率也是不同的,對於數據的一致性保證也就有不同的結果。而這些可能出現的又有哪些呢?
臟讀(dirty read)
當事務與事務之間沒有任何隔離的時候,就可能會出現臟讀。例如:商家想看看所有的訂單有哪些,這時,用戶A提交了一個訂單,但事務還沒提交,商家卻看到了這個訂單。而這時就會出現一種問題,當商家去操作這個訂單時,可能用戶A的訂單由於部分問題,導致數據回滾,事務沒有提交,這時商家的操作就會失去目標。
不可重復讀(unrepeatable read)
一個事務中,兩次讀操作出來的同一條數據值不同,就是不可重復讀。
例如:我們有一個事務A,需要去查詢一下商品庫存,然後做扣減,這時,事務B操作了這個商品,扣減了一部分庫存,當事務A再次去查詢商品庫存的時候,發現這一次的結果和上次不同了,這就是不可重復讀。
幻讀(phantom problem)
一個事務中,兩次讀操作出來的結果集不同,就是幻讀。
例如:一個事務A,去查詢現在已經支付的訂單有哪些,得到了一個結果集。這時,事務B新提交了一個訂單,當事務A再次去查詢時,就會出現,兩次得到的結果集不同的情況,也就是幻讀了。
那針對這些結果,不同的隔離級別可以干什麼呢?
「讀未提(Read Uncommitted)」能預防啥?啥都預防不了。
「讀提交(Read Committed)」能預防啥?使用「快照讀(Snapshot Read)」方式,避免「臟讀」,但是可能出現「不可重復讀」和「幻讀」。
「可重復讀(Repeated Red)」能預防啥?使用「快照讀(Snapshot Read)」方式,鎖住被讀取記錄,避免出現「臟讀」、「不可重復讀」,但是可能出現「幻讀」。
「串列化(Serializable)」能預防啥?有效避免「臟讀」、「不可重復讀」、「幻讀」,不過運行效率奇差。
好了,鎖說完了,但是,我們的資料庫鎖,並不能有效的解決並發的問題,只是盡可能保證數據的一致性,當並發量特別大時,資料庫還是容易扛不住。那解決數據並發的另一個手段就是,盡可能的提高處理的速度。
因為數據的IO要提升難度比較大,那麼通過其他的方式,對數據進行處理,減少資料庫的IO,就是提高並發能力的有效手段了。
最有效的一種方式就是:緩存
想要減少並發出現的概率,那麼讀寫的效率越高,讀寫的執行時間越短,自然數據並發的可能性就變小了,並發性能也有提高了。
還是用剛才的秒殺舉例,我們為的就是保證庫存的數據不出錯,賣出一個商品,減一個庫存,那麼,我們就可以將庫存放在內存中進行處理。這樣,就能夠保證庫存有序的及時扣減,並且不出現問題。這樣,我們的資料庫的寫操作也變少了,執行效率也就大大提高了。
當然,常用的分布式緩存方式有:Redis和Memcache,Redis可以持久化到硬碟,而Memcache不行,應該怎麼選擇,就看具體的使用場景了。
當然,緩存畢竟使用的范圍有限,很多的數據我們還是必須持久化到硬碟中,那我們就需要提高資料庫的IO能力,這樣避免一個線程執行時間太長,造成線程的阻塞。
那麼,讀寫分離就是另一種有效的方式了
當我們的寫成為了瓶頸的時候,讀寫分離就是一種可以選擇的方式了。
我們的讀庫就只需要執行讀,寫庫就只需要執行寫,把讀的壓力從主庫中分離出去,讓主庫的資源只是用來保證寫的效率,從而提高寫操作的性能。
㈤ mysql的事務四個特性以及事務的四個隔離級別
分別是原子性、一致性、隔離性、持久性。
原子性是指事務包含的所有操作要麼全部成功,要麼全部失敗回滾,因此事務的操作如果成功就必須要完全應用到資料庫,如果操作失敗則不能對資料庫有任何影響。
一致性是指事務必須使資料庫從一個一致性狀態變換到另一個一致性狀態,也就是說一個事務執行之前和執行之後都必須處於一致性狀態。舉例來說,假設用戶A和用戶B兩者的錢加起來一共是1000,那麼不管A和B之間如何轉賬、轉幾次賬,事務結束後兩個用戶的錢相加起來應該還得是1000,這就是事務的一致性。
隔離性是當多個用戶並發訪問資料庫時,比如同時操作同一張表時,資料庫為每一個用戶開啟的事務,不能被其他事務的操作所干擾,多個並發事務之間要相互隔離。關於事務的隔離性資料庫提供了多種隔離級別,稍後會介紹到。
持久性是指一個事務一旦被提交了,那麼對資料庫中的數據的改變就是永久性的,即便是在資料庫系統遇到故障的情況下也不會丟失提交事務的操作。例如我們在使用JDBC操作資料庫時,在提交事務方法後,提示用戶事務操作完成,當我們程序執行完成直到看到提示後,就可以認定事務已經正確提交,即使這時候資料庫出現了問題,也必須要將我們的事務完全執行完成。否則的話就會造成我們雖然看到提示事務處理完畢,但是資料庫因為故障而沒有執行事務的重大錯誤。這是不允許的。
在資料庫操作中,在並發的情況下可能出現如下問題:
正是為了解決以上情況,資料庫提供了幾種隔離級別。
資料庫事務的隔離級別有4個,由低到高依次為Read uncommitted(未授權讀取、讀未提交)、Read committed(授權讀取、讀提交)、Repeatable read(可重復讀取)、Serializable(序列化),這四個級別可以逐個解決臟讀、不可重復讀、幻象讀這幾類問題。
雖然資料庫的隔離級別可以解決大多數問題,但是靈活度較差,為此又提出了悲觀鎖和樂觀鎖的概念。
悲觀鎖,它指的是對數據被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)修改持保守態度。因此,在整個數據處理過程中,將數據處於鎖定狀態。悲觀鎖的實現,往往依靠資料庫提供的鎖機制。也只有資料庫層提供的鎖機制才能真正保證數據訪問的排他性,否則,即使在本系統的數據訪問層中實現了加鎖機制,也無法保證外部系統不會修改數據。
商品t_items表中有一個欄位status,status為1代表商品未被下單,status為2代表商品已經被下單(此時該商品無法再次下單),那麼我們對某個商品下單時必須確保該商品status為1。假設商品的id為1。
如果不採用鎖,那麼操作方法如下:
但是上面這種場景在高並發訪問的情況下很可能會出現問題。例如當第一步操作中,查詢出來的商品status為1。但是當我們執行第三步Update操作的時候,有可能出現其他人先一步對商品下單把t_items中的status修改為2了,但是我們並不知道數據已經被修改了,這樣就可能造成同一個商品被下單2次,使得數據不一致。所以說這種方式是不安全的。
在上面的場景中,商品信息從查詢出來到修改,中間有一個處理訂單的過程,使用悲觀鎖的原理就是,當我們在查詢出t_items信息後就把當前的數據鎖定,直到我們修改完畢後再解鎖。那麼在這個過程中,因為t_items被鎖定了,就不會出現有第三者來對其進行修改了。需要注意的是,要使用悲觀鎖,我們必須關閉mysql資料庫的自動提交屬性,因為MySQL默認使用autocommit模式,也就是說,當你執行一個更新操作後,MySQL會立刻將結果進行提交。我們可以使用命令設置MySQL為非autocommit模式: set autocommit=0;
設置完autocommit後,我們就可以執行我們的正常業務了。具體如下:
上面的begin/commit為事務的開始和結束,因為在前一步我們關閉了mysql的autocommit,所以需要手動控制事務的提交。
上面的第一步我們執行了一次查詢操作: select status from t_items where id=1 for update; 與普通查詢不一樣的是,我們使用了 select…for update 的方式,這樣就通過資料庫實現了悲觀鎖。此時在t_items表中,id為1的那條數據就被我們鎖定了,其它的事務必須等本次事務提交之後才能執行。這樣我們可以保證當前的數據不會被其它事務修改。需要注意的是,在事務中,只有 SELECT ... FOR UPDATE 或 LOCK IN SHARE MODE 操作同一個數據時才會等待其它事務結束後才執行,一般 SELECT ... 則不受此影響。拿上面的實例來說,當我執行 select status from t_items where id=1 for update; 後。我在另外的事務中如果再次執行 select status from t_items where id=1 for update; 則第二個事務會一直等待第一個事務的提交,此時第二個查詢處於阻塞的狀態,但是如果我是在第二個事務中執行 select status from t_items where id=1; 則能正常查詢出數據,不會受第一個事務的影響。
使用 select…for update 會把數據給鎖住,不過我們需要注意一些鎖的級別,MySQL InnoDB默認Row-Level Lock,所以只有「明確」地指定主鍵或者索引,MySQL 才會執行Row lock (只鎖住被選取的數據) ,否則MySQL 將會執行Table Lock (將整個數據表單給鎖住)。舉例如下:
1、 select * from t_items where id=1 for update;
這條語句明確指定主鍵(id=1),並且有此數據(id=1的數據存在),則採用row lock。只鎖定當前這條數據。
2、 select * from t_items where id=3 for update;
這條語句明確指定主鍵,但是卻查無此數據,此時不會產生lock(沒有元數據,又去lock誰呢?)。
3、 select * from t_items where name='手機' for update;
這條語句沒有指定數據的主鍵,那麼此時產生table lock,即在當前事務提交前整張數據表的所有欄位將無法被查詢。
4、 select * from t_items where id>0 for update; 或者 select * from t_items where id>1 for update; (註:>在SQL中表示不等於)
上述兩條語句的主鍵都不明確,也會產生table lock。
5、 select * from t_items where status=1 for update; (假設為status欄位添加了索引)
這條語句明確指定了索引,並且有此數據,則產生row lock。
6、 select * from t_items where status=3 for update; (假設為status欄位添加了索引)
這條語句明確指定索引,但是根據索引查無此數據,也就不會產生lock。
樂觀鎖( Optimistic Locking ) 相對悲觀鎖而言,樂觀鎖假設認為數據一般情況下不會造成沖突,所以只會在數據進行提交更新的時候,才會正式對數據的沖突與否進行檢測,如果發現沖突了,則返回用戶錯誤的信息,讓用戶決定如何去做。實現樂觀鎖一般來說有以下2種方式:
㈥ mysql隔離級別
MySQL 中事務的隔離級別一共分為四種,分別如下:
序列化(SERIALIZABLE):如果隔離級別為序列化,則用戶之間通過一個接一個順序地執行當前的事務,這種隔離級別提供了事務之間最大限度的隔離。
可重復讀(REPEATABLE READ):在可重復讀在這一隔離級別上,事務不會被看成是一個序列。不過,當前正在執行事務的變化仍然不能被外部看到,也就是說,如果用戶在另外一個事務中執行同條 SELECT 語句數次,結果總是相同的。(因為正在執行的事務所產生的數據變化不能被外部看到)。
提交讀(READ COMMITTED):READ COMMITTED 隔離級別的安全性比 REPEATABLE READ 隔離級別的安全性要差。處於 READ COMMITTED 級別的事務可以看到其他事務對數據的修改。也就是說,在事務處理期間,如果其他事務修改了相應的表,那麼同一個事務的多個 SELECT 語句可能返回不同的結果。
未提交讀(READ UNCOMMITTED):READ UNCOMMITTED 提供了事務之間最小限度的隔離。除了容易產生虛幻的讀操作和不能重復的讀操作外,處於這個隔離級的事務可以讀到其他事務還沒有提交的數據,如果這個事務使用其他事務不提交的變化作為計算的基礎,然後那些未提交的變化被它們的父事務撤銷,這就導致了大量的數據變化。
應用環境
與其他的大型資料庫例如Oracle、DB2、SQL Server等相比,MySQL自有它的不足之處,但是這絲毫也沒有減少它受歡迎的程度。對於一般的個人使用者和中小型企業來說,MySQL提供的功能已經綽綽有餘,而且由於 MySQL是開放源碼軟體,因此可以大大降低總體擁有成本。