【mybatis】mybatis JDBC事務細節

一、JDBC事務鋪墊

    在JDBC事務操作中,conn.commit()和conn.setAutocommit(true)擁有相同的數據庫操作效果,都會提交事務持久化對數據庫的更改,這一點隨便寫個JDBC基本操作的demo就能夠得到驗證。


二、mybatis DQL

    查看mybatis openSession的源碼,除非傳入boolean autoCommit=true,否則默認都是false。

    因此mybatis的事務機制,無論是查詢還是增刪改,默認都會執行conn.setAutocommit(false),這句話會導致數據庫關閉自動提交和開啓事務(基本的JDBC demo已驗證);在SqlSession關閉的時候會conn.setAutocommit(true),這裏會提交事務。在使用基本的mybatis query的時候,最後是需要關閉SqlSession,如果忘記了這一步,在連接池機制下,會造成事務泄露,也就是說conn沒有關閉,但是conn的事務一直沒有提交。


三、mybatis DML

    DML也會默認conn.setAutocommit(false),但是mybatis的DML需要顯示的SqlSession.commit(),否則在close的時候會回滾事務。這個細節的實現在於SqlSession中的一個標誌位boolean dirty,這個標誌位在SqlSession初始化的時候默認爲false,在進行DML的時候會賦值爲true,當commit的時候,再次被修改成false,close的時候會檢查該標誌位,如果爲true,則會回滾事務,否則關閉連接(重置autocommit=true,連接池機制下是還會連接池)。

    也就是說,如果不commit,則不會持久化數據庫操作,在SqlSession close的時候,回滾事務,然後重置autocommit=true,然後關閉連接;如果commit,但是沒有close,那麼提交了事務,但是沒有把連接還會連接池,這樣的失誤會在連接池popConnection的時候得到補救(請查看源碼邏輯);如果既沒有commit,也沒有close,則會造成事務泄露。


四、總結

    A. 對於DQL,你得session.close(),否則事物泄露;

    session.close()方法會提交事務和關閉連接,搭配dirty標誌可以控制事物是否回滾;在整個DQL過程中,dirty標誌位始終沒有更改,一直都是false,因此在close的時候並不會回滾,在關閉連接的時候,會根據連接池類型將連接設置回自動提交;而DML則沒有必要commit事物,因爲標誌位dirty爲false,因此不會提交事務,則session.commit()方法是否調用並無必要。

    B. 對於DML,沒有commit和close,則事物不提交、連接不關閉,有commit沒有close,則事物提交但是連接泄露,有close沒有commit,則事務回滾;

    當進行DML的時候,dirty標誌位會修改爲true;在進行事務提交的時候,會connection.commit(),向數據庫提交事務,然後將dirty標誌位修改爲false;此時在進行事物關閉dirty=false則不會導致回滾,並在事物關閉的同時根據連接池類型將連接重置或關閉或還回池中;倘若沒有commit,則會導致事務回滾;倘若沒有close,則會導致事物和連接泄露。

    當然,在xml文件中配置數據源的時候,有一個超時的配置(當type=POOLED或其他數據源的配置),當採用POOLED的時候,其默認超時是protected int poolMaximumCheckoutTime = 20000,即20s過期,因此連接泄露的最小時間是20s。


附註:

    本文如有錯漏,煩請不吝指正,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章