前幾天我發了這篇文章《我來出個題:這個事務會不會回滾?》獲得了不少不錯的反饋,也有很多讀者經過微信、羣或者郵件的方式,給了我一些關於test4的回覆。其中還有直接發給我測試案例,來證實個人答案是錯的。今天,咱們就來一塊兒看看test4這個爭議很大的問題。若是您是剛打開這篇文章,不瞭解咱們在討論啥,那能夠先點擊查看以前的這篇《我來出個題:這個事務會不會回滾?》。經過這兩篇文章的解析,相信你會對Spring Data JPA下的事務執行機制有質的飛躍。html
先來講說,那些寫了代碼驗證"不會回滾"的狀況,把這些錯誤答案的緣由先說清楚,而後再細說test4會回滾的狀況。java
根據這兩天讀者給個人案例或者描述清楚的一些狀況,歸結了一下,你們寫的驗證代碼之因此不會回滾,主要有如下三個緣由:spring
歸家一下出現這些疑問的緣由:沒審題和事務基礎掌握不牢致使。關於事務基礎使用的一些常見注意點,以前寫過一篇文章,若是以爲這方面知識還不紮實的,建議讀一讀:《爲何加了@Transactional註解,事務沒有回滾?》微信
先來看看執行時候報的異常:函數
javax.validation.ConstraintViolationException: Validation failed for classes [com.didispace.chapter310.User] during persist time for groups [javax.validation.groups.Default, ] List of constraint violations:[ ConstraintViolationImpl{interpolatedMessage='個數必須在0和5之間', propertyPath=name, rootBeanClass=class com.didispace.chapter310.User, messageTemplate='{javax.validation.constraints.Size.message}'} ] at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:140) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:80) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.action.internal.EntityInsertAction.preInsert(EntityInsertAction.java:209) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:83) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:511) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3283) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2479) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final] at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:98) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
這個異常是這個回滾的關鍵。這個異常javax.validation.ConstraintViolationException
是哪裏的呢?還記得之前說的JSR 303不?對的,是Bean Validation中的異常。學習
有的讀者說這個不是RuntimeException
,因此不會回滾。很顯然,這類判斷的都沒有實際嘗試一下,只要點開源碼能夠立刻發現,這個異常就是屬於RunTimeException
的。測試
實際上,之因此會回滾,與這裏使用Spring Data JPA以及Hibernate Validator有直接關係。從JPA 2.0開始,就默認支持了這些Bean Validation的實現,它提供了實體生命週期中pre-persist
, pre-update
,pre-remove
三個事件發生時來執行校驗的功能。而在校驗的時候,當校驗失敗,拋出javax.validation.ConstraintViolationException
時,當前事務就會被標記爲rollback
。this
要想了解,這其中到底發生了什麼,跟蹤源碼是最好的方式。那麼源碼從哪裏開始看呢?從異常日誌中找線索吧。spa
從異常棧中找到最近的一個錯誤,點開看看。hibernate
錯誤行數在532行tx.commit()
,習慣性的加上斷點,這樣下一次進來的時候能夠看看當前狀況下的各類參數狀況。
同時看到下面還有個catch,既然532行出錯了,那這裏確定會進,因此也加個端點,到時候能夠進去看看。
執行程序,調用一下test4,執行到532行,而後進入下一步,看看會到哪裏?
這個時候,會進入到org.hibernate.engine.transaction.internal.TransactionImpl
,具體位置以下:
仍是習慣性的,在下面兩行重要位置加上斷點,以便下次能夠快速到這裏。
繼續按上看的步驟嘗試下去,能夠來到下圖的位置:
能夠看到校驗異常是從271行出來的,結合278行和280行,是否是清楚這裏回滾的緣由了呢?
實踐出真知,當你以爲困惑的時候,不如動手寫一寫,調一調,不少答案就能天然浮現!
若是對於test4會回滾還不夠理解,或者你還有其餘事務執行不如預期的讀者,那就跟着個人思路,一步步嘗試一下,能夠觀察的更深刻一些,你對這部分邏輯的理解就更全面了。咱們正在組建高質量的Spring技術交流羣,歡迎各類熱愛技術的開發者加入參與討論。這裏的每一個人都有本身的閃光點,互相學習,取長補短,長期堅持,願你們都會成爲本身領域裏的佼佼者!
歡迎關注個人公衆號:程序猿DD,分享其餘地方看不到的知識與思考