數據庫新增了一條數據,但是查詢不到,是代碼玄學么?


一、背景  

  今天遇到了一個很奇葩的bug,是這樣的。我在一個service里面執行了4步操作(流程圖如下):

  1)給表1新增了一條數據;

  2)根據表1新增的結果,給表2新增一條數據;

  3)根據表2插入的結果,異步調用第三方接口。然后他們處理完了之后以MQ的形式告訴我的服務;

  4)如果調用第三方接口成功,繼續處理剩下的邏輯。

  

  遇到的問題是:我收到第三方的MQ后,有時查表1中新增的數據查不到,但是數據庫里面明明有的啊。另外,為啥偶爾查不到呢?難道有代碼玄學在作怪么?

  

 

二、原因

  究其原因,是 數據庫事務在作怪,也怪我當初學習的時候只是背了概念,沒有深刻的去理解它。當時代碼上面有有一個注解@Transactional,看了它的源碼,不聲明隔離級別時,它是使用數據庫默認的隔離級別。我們知道mysql默認的隔離級別時“可重復讀” (讀未提交——讀已提交——可重復讀——串行化)。所以就清楚了,當收到第三方的MQ之后,由於之前的事務沒有提交,所以當然查不到數據了。

@Transactional(rollbackFor = {RuntimeException.class, OptimusExceptionBase.class})
@Override
public void xxx(){
  //邏輯處理
}
/**
   * Use the default isolation level of the underlying datastore.
   * All other levels correspond to the JDBC isolation levels.
   * @see java.sql.Connection
   */
Isolation isolation() default Isolation.DEFAULT;

 

三、解決辦法

  方案一:在收到MQ的那個service里面,可以將隔離級別設置為“讀未提交”;

  方案二:在調用第三方的那個service里面,去掉事務,這樣只要有數據庫的“寫操作”,則立馬會得到數據庫的響應,不會受后續代碼寫數據庫的影響,完全是單獨的。當然缺點是需要自己控制事務的執行與回滾;

  方案三:可能情況下,調整代碼流程,將調用第三方的操作放在最后,調用第三方結束則方法結束。

 

四、其他情況

  還有一種情況也會發生“插入數據,讀取不到”。當數據庫配置了讀寫分離后,寫數據庫會寫主庫,而讀數據會讀從庫。這樣在網絡延遲比較高的情況下,可能發生主從延遲——在主庫新插入的數據還沒有同步到從庫,導致查詢從庫查詢不到。對於這種問題,解決辦法就好多了,具體用那種根據自己的業務決定:

  1)降低主從延遲;

  2)優化代碼邏輯,為啥插入了還要讀取;

  3)開啟半同步復制,即數據同步到了從庫才算真正的插入。

 


免責聲明!

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



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