catalogue
1. The access type of the method is not public
3. Circular call and not managed by Spring
4. Pay attention to multi-threaded scenarios
6. Exceptions thrown in transaction methods are caught
7. Transaction communication mechanism
Referring to the figure of Daiwen senior and someone on Tiktok, (summarized it a long time ago but didn't take notes) the summary written in the Internet cafe (absolutely personal experience), there's no way
1. The access type of the method is not public
When the modifier accessed by the transaction method is non public, the transaction will be invalidated
There are four kinds of access permissions in java: private, default, protected and public. The permissions increase from left to right. If our addUser method changes to other access types, it will fail
@Service public class EmpService { @Transactional private void addUser(UserModel userModel){ saveData(userModel); }
Let's see how Spring's source code explains if it is not a public target method. Then TransactionAttribute returns null and does not support transactions
2. Cannot be final
Then the problem comes. If I use this method a little more, what about public+final decoration?
When the method is decorated by final, the transaction will also be invalidated
Explanation: as we all know, our Spring transaction bottom layer uses AOP (in essence, dynamic proxy, that is, reflection, which involves a lot of knowledge points), jdk dynamic proxy or cglib (I will say it separately at that time, one is an essential implementation interface, the other is an inherited parent class rewrite Implementation) - > to help us generate proxy classes and realize transaction functions in proxy classes;
Summary: so, you are all final. How can you rewrite or implement this method?, So you can't add transactions
In depth, we need to think about it in combination with JVM class loading + Klass model in it (I haven't changed some problems in it, and it's too lazy). Here, some people who watch a Spring video and talk about it everywhere are diss, keep a low profile, Hahahahahaha
Dynamic agent review_ Fair wants carry's blog -CSDN blog
Java reflection perception_ Fair wants carry's blog -CSDN blog
Class loading some understanding (-)_ Fair wants carry's blog -CSDN blog
jvm memory model and local memory_ Fair wants carry's blog -CSDN blog_ jvm memory and local memory
@Service public class EmpService { @Transactional public final void addUser(UserModel user){ save(user); } }
3. Circular call and not managed by Spring
Remember the circular calls between methods. This also happens in the demo written before. If a method is managed by Spring, then if there is another method that calls each other in it, remember that another method that calls each other cannot be managed by Spring, and circular dependency has the same meaning;
In addition, it will fail if it is not managed by Spring
4. Pay attention to multi-threaded scenarios
If another thread in a transaction method add calls an update method in the transaction method add, the add transaction will also fail, because two different threads execute the two methods, then the database connections obtained are different, so there are two different transactions. If an exception is thrown in the update method, the add method will not rollback
@Service public class EmpService { @Autowired private OrderService orderService; @Transactional public void add(User user){ new Thread(()->{ orderService.update(); }).start(); } } @Service public class OrderService{ @Transactional public void update(){ System.out.println("======================"); } }
Note: spring transactions are implemented through database connections. A map is saved in the current thread. key is the data source and value is the database connection. The same transaction refers to the same database connection. Only having the same transaction connection can ensure simultaneous commit and rollback. If it is a different thread, the database connection will be different.
5. Database engine
When the database engine does not use innodb, it will also cause transaction failure
SQL advanced_ Fair wants carry's blog -CSDN blog
6. Exceptions thrown in transaction methods are caught
Explanation: to put it simply, if we handle the exception manually in the @transverse transaction method, our Spring will not receive the exception, so how can we rollback - >throw solution, and it is best to throw RuntimeException, otherwise the efficiency is relatively low, why?
In fact, if you have a deep understanding of reflection and class loading, you will know, because our transaction essence is actually based on the dynamic agent idea of reflection implementation, The purpose is to execute our target class methods through the invoke Method in the InvocationHandler interface under the reflection package, and then enhance -- > the essence is to call the member methods in the Method area through the class object of our target class (in Java code, such as: xxx.class.getMethod(), so as to get our Method, and then invoke execution is over)
7. Transaction communication mechanism
If the propagation property of a transaction is set incorrectly, the transaction will also fail. As follows: propagation = propagation The propagation feature of never does not support transactions. If there are transactions, an exception will be thrown.
At present, only these three propagation features can create new things: REQUIRED and REQUIRES_NEW,NESTED
@Service public class EmpService { @Transactional(propagation = Propagation.NEVER) public void add(User user){ saveData(user); updateSataus(user); } }
8. Nested transactions
For such code. If the saveData execution succeeds and the updataStatus execution fails, the entire add method will be rolled back. Then the method that saveData executed successfully before will also be rolled back
@Service public class EmpService { @Autowired private OrderService orderService; @Transactional public void add(User user) { saveData(user); orderService.updateSataus(); } } @Service public class OrderService(){ @Transactional(propagation = Propagation.NESTED) public void updateSataus(){ System.out.println("======================"); } }
What if our goal is to rollback only the methods that report errors? (however, in general business scenarios, it seems that there are many rollback, which is what I wrote. Similar to the XA mode of seata, it is directly and strongly consistent.)
@Service public class EmpService { @Autowired private OrderService orderService; @Transactional public void add(UserModel userModel) { saveData(userModel); try { orderService.updateSataus(); } catch (Exception e) { e.printStackTrace(); } } } @Service public class OrderService(){ @Transactional(propagation = Propagation.NESTED) public void updateSataus(){ System.out.println("======================"); } }