天天看點

spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!

  項目架構主要是spring,持久層架構沒有用mybtis,用的是spring 的jdbc;

  業務需求:給應用添加領域(一個領域包含多個應用,一個應用可能屬于多個領域,一般而言一個應用隻屬于一個領域),要求是給應用添加領域的時候,先将該應用已有的領域都删除,之後再将選中的領域添加到資料庫;

  為了減少準備工作,我利用了以前的代碼和資料模組化,那麼就成了:添加person的時候先删除已存在name為新添加person的name的person,再添加新person,說直白點就是:添加name為zhangsan的person,那麼先删除資料庫中name為zhangsan的所有person資訊,然後再将新的zhangsan的person資訊添加到資料庫中;

  環境搭建過程我就不寫了,完整代碼會以附件形式上傳;

  注意:druid連接配接池一般而言,jdbc設定成自動送出,不設定的話,預設也是自動送出(有興趣的朋友可以去看下druid連接配接池的源碼)

  先來驗證下,目前jdbcTempalte是否是自動送出的,如何驗證了,我可以在jdbcTemplate執行完之後抛出一個異常,代碼如下  

  沒有配置事務

spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!
spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!

View Code

spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!
spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!
spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!

  那麼如果直接像如下方式來處理先删後加是不行的,如果删成功添加失敗,那麼資料庫的資料卻隻是删了而沒有添加成功

  為了保證事務一緻性,第一時間想到了jdbcTemplate是否有事務相關設定,然而并沒有發現,但是發現了jdbcTemplate.getDataSource().getConnection(),于是飛快的寫了如下代碼:

  本以為實作事務一緻性,可執行結果如下:                                        

spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!
spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!
spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!

   發現沒有實作事務一緻性,這是為什麼??????? 這裡先留個懸念,大家好好思考下;當時我也沒去仔細研究,因為完成任務才是第一要緊事,緊接着寫出了如下代碼:

   詭異的事情來了,居然和上面的情況一樣:删除成功,添加失敗! 我的天老爺,這是怎麼回事????

spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!
spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!
spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!

  瞬間懵逼了,怎麼回事?代碼怎麼改都不行!!!

    檢視資料庫引擎,發現引擎是MyISAM!  瞬間爆炸!!!!

spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!
spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!

  将引擎改成InnoDB後,手動送出2的代碼是能夠保證事務一緻性的,那麼手動送出1的代碼是不是也能保證事務一緻性了? 此處再留一個懸念,希望各位觀衆老爺們好好思考下。

  任務雖然完成了,可是無論是手動送出2,還是手動送出1(姑且認為能保證事務一緻性),代碼的try catch簡直讓人無法接受;映像中,spring有事務管理,那麼就來看看事務交給spring如何實作

  配置事務管理器:

spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!
spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!

  配置事務

  執行結果如下:

spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!
spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!
spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!

  這代碼清爽多了,要的就是這種感覺!! 就是這個feel倍兒爽,爽爽爽爽!

  搭建這個工程的用到了lombok,不知道的可以去百度下,我這裡就想提醒下,這玩意和一般的jar有差別,他需要安裝,不然編譯不通過! 喜歡搞事的jar;

  另外druid連接配接池對mysql驅動是有版本要求的,mysql驅動5.1.10是會在連接配接池初始化的時候報錯的,具體是從哪個版本開始不報錯我就沒去逐個試了,知道的朋友可以留個言,本工程中用的是5.1.25版本;

spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!
spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!

  懸念解答:

    還記得是哪兩個懸念嗎?  1、手動送出1不能保證事務一緻性是不是mysql引擎引起的;  2、如果mysql引擎是支援事務的InnoDB,手動送出1能不能保證事務一緻性;

    關于懸念1,這個很明了,如果mysql引擎不支援事務,那麼代碼無論怎麼寫,事務一緻性都是空談;

    懸念2的話,是能肯定的回答:不能保證事務一緻性的! 因為jdbcTemplate.getDataSource().getConnection()擷取的connection與每次jdbcTemplate.update用到的connection都是從連接配接池中擷取的,不能保證是一個connection,那怎麼保證事務一緻性; 感興趣的朋友可以去閱讀源碼,裡面各種黃金、各種美女哦!

spring jdbcTemplate 事務,各種詭異,包你醍醐灌頂!

  那麼問題又來了,既然jdbcTemplate每次執行一個操作的時候都是從連接配接池中擷取connection,那麼spring事務管理是如何保證同個事務的呢?

  更多精彩内容請看:Spring 事務源碼解析 → 它是如何保證同個事務的

  本文附件

繼續閱讀