A few days ago I posted this article "I'll ask a question: Will this transaction be rolled back? 》 got a lot of good feedback, and many readers gave me some replies about test4 through WeChat, group or email. There are also test cases sent directly to me to prove that my answer is wrong. Today, let's take a look at the very controversial issue of test4. If you just opened this article and don’t know what we’re discussing, you can click to view the previous "I’m here to ask a question: Will this transaction roll back? " . Through the analysis of these two articles, I believe you will make a qualitative leap in the transaction execution mechanism under Spring Data JPA.
Why didn't you roll back
Let me talk about those "will not roll back" . First explain the reasons for these wrong answers, and then elaborate on the circumstances under which test4 will roll back.
Based on the cases that readers gave me in the past two days or some clearly described situations, it can be concluded that the verification code you wrote will not roll back mainly due to the following three reasons:
- I did not follow what I said at the beginning of the topic, using the InnoDB storage engine, using MyISAM, does not support transactions, and naturally will not reproduce.
- It's useless. According to what I said at the beginning of the topic, I use JPA and JSR 303 to verify annotations, such as: MyBaits is used, so naturally it will not recur.
- The function that defines the transaction is not a public type, this basic usage is wrong, the transaction itself does not take effect
The reason for these questions when you home: 160e50aaabb42c did not review the questions and transaction basis caused by inadequate grasp. Regarding some common points of attention in the use of transaction basics, I wrote an article before. If you feel that this knowledge is not solid, I suggest you read it: "Why the @Transactional annotation is added and the transaction is not rolled back? 》
Why does the catch roll back?
Let's take a look at the exception reported during execution:
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]
This exception is the key to this rollback. Where is this exception javax.validation.ConstraintViolationException
Remember the JSR 303 mentioned before? Yes, it is an exception in Bean Validation.
Some readers say this is not RuntimeException
, so it will not roll back. Obviously, I haven't actually tried this kind of judgment. As long as you click on the source code, you can immediately find that this exception belongs to RunTimeException
.
In fact, the reason for the rollback is directly related to the use of Spring Data JPA and Hibernate Validator. Since JPA 2.0, the implementation of these Bean Validation has been supported by default. It provides the function of performing validation when three events pre-persist
, pre-update
, pre-remove
During verification, when the verification fails and javax.validation.ConstraintViolationException
is thrown, the current transaction will be marked as rollback
.
Source code analysis
If you want to understand what happened in this, tracking the source code is the best way. So where do you start looking at the source code? Look for clues in the exception log.
Find the most recent error from the exception stack and click to open it.
The number of error lines is in line 532, tx.commit()
, and breakpoints are added habitually, so that the next time you come in, you can look at the various parameters in the current situation.
At the same time, I see that there is a catch below. Since line 532 is wrong, it will definitely be entered here, so I also add an endpoint, then you can go in and have a look.
Execute the program, call test4, execute to line 532, and then go to the next step to see where it will go?
At this time, you will enter org.hibernate.engine.transaction.internal.TransactionImpl
, the specific location is as follows:
It is still habitual to add breakpoints to important positions in the following two lines so that you can get here quickly next time.
Continue to try the steps shown above, and you can come to the position shown in the figure below:
You can see that the checksum exception is from line 271, combined with line 278 and line 280, is it clear why the rollback is here?
Practice gives you real knowledge. When you feel confused, it is better to write by hand and adjust the tune. Many answers will naturally emerge!
If you don’t understand enough about the rollback of test4, or if you have other readers whose transaction execution is not as expected, then follow my ideas and try step by step. You can observe more deeply, and your understanding of this part of the logic will be better. It's comprehensive. We are forming a high-quality Spring technology exchange group . Developers who love technology are welcome to join the discussion. Everyone here has their own shining points, learn from each other, learn from each other's strengths, and persevere for a long time, I hope everyone will become the best in their field!
Welcome to pay attention to my public account: Program Ape DD, share knowledge and thoughts that can’t be seen elsewhere
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。