數據庫事務的四大特性


一個設計良好的數據庫可以幫我們保證事務具有四大特性(ACID):

原子性:原子性是指事務是一個不可分割的工作單位,事務中的操作要么都發生,要么都不發生。

一致性:如果事務執行之前數據庫是一個完整的狀態,那么事務結束后,無論事務是否執行成功,數據庫仍然是一個完整的狀態。

  數據庫的完整狀態:當一個數據庫中的所有的數據都符合數據庫中所定義的所有約束,此時可以稱數據庫是一個完整的狀態。

隔離型:多個用戶並發訪問數據庫時,一個用戶的事務不能被其他用戶的事務所干擾,多個並發事務之間數據要相互隔離。

持久性:指一個事務一旦被提交,他對數據庫的影響是永久性的。

 

數據庫可以保證原子性,一致性,持久性。但是隔離級別需要根據並發情況進行設置,

將數據庫設計成單線程,可以防止所有的線程安全問題,自然也就保證了隔離型的問題,但是如果這樣,那么效率就會極其低下。

如果兩個線程並發修改,一定會相互搗亂,這時必須利用鎖機制防止多個線程的並發修改

如果兩個線程並發查詢,沒有線程安全問題。

如果兩個線程一個修改,一個查詢:

  四大隔離級別:

  Read uncommitted:---不防止任何隔離型問題,不能防止臟讀/不可重復讀/幻讀問題。

  Read commit:---可以防止臟讀問題,但是不能防止 不可重復讀/幻讀問題。(oracle默認隔離級別)

  Repeatable read:---可以防止臟讀/不可重復讀,不能防止幻讀。(mysql默認隔離級別)

  Serializable:--數據庫被設計為單線程,可以防止上述所有問題

  臟讀:一個事務讀取到另一個事務未提交的數據。

  場景:a賬戶1000,b賬戶1000,a到b的網店里買一百塊錢的鞋子。。。。

  a:start transaction

  update table set money=money-100 where name='a';//a賬戶扣除100

  update table set money=money+100 where name='b';//b賬戶增加100

  此時a還沒有提交事務,對b說付款成功

  b:start transaction;//b開始查詢自己的賬戶余額

  select money form table where name='b';

  b:commit;

  如果讀取到了a沒有提交的數據,那么b查出來的就會是1100,此時b開始發貨

  此時a執行回滾

  a:rollback;

  那么b再去查詢賬戶余額會發現自己的賬戶還是原先的100塊

 

  不可重復讀:在當前事務中,讀取到了另一事務提交的更新和刪除的數據。

  場景:如果a有活期資金1000,定期1000,固定資產1000

  a: 1000 1000 1000
  b: 銀行職員,銀行讓職員b算出a客戶的總共資產
  ---------
  b:start transaction;
  select 活期存款 from account where name='a'; ---- 活期存款:1000
  select 定期存款 from account where name='a'; ---- 定期存款:1000
  select 固定資產 from account where name='a'; ---- 固定資產:1000
    -------此時a客戶取走了自己活期的1000元
    a:
    start transaction;
    update accounset set 活期=活期-1000 where name='a';
    commit;
  -------
  select 活期+定期+固定 from account where name='a'; --- 總資產:2000,按照之前查出來的應該是3000元,但是現在是2000元
  commit;
  ----------

  但是雖然在這種場景下,出現了不可重復讀,但是如果在另一場景下,如果你和你的伙伴共用一個銀行賬戶共100萬,你的伙伴如果中途取走了50萬,而你此時讀取到剩下的50萬,就符合該場景。

  幻讀:在當前事務中,讀取到了另一事務提交的插入的數據

  場景:如果銀行現在有a、b兩位客戶存款各1000,銀行老板讓職員b去算平均每個客戶的平均存款,而又有新增客戶c存入了4000元。

  a: 1000
  b: 1000
  d: 銀行業務人員

  -----------
  d:
  start transaction;
  select sum(money) from account; --- 2000 元
  select count(name) from account; --- 2 個

  ------
  c:
start transaction;
insert into account values(c,4000);
commit;
------

select sum(money)/count(name) from account; --- 平均:2000元/個,結果應該是平均存款1000,而實際結果確實2000
commit;
------------

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM