当前位置:网站首页>Meituan side: @transactional principle and common pits?
Meituan side: @transactional principle and common pits?
2022-07-17 23:53:00 【Hollis Chuang】
Here is DB Data and DB Operation interface :
| uid | uname | usex |
|---|---|---|
| 1 | Zhang San | Woman |
| 2 | Chen Heng | male |
| 3 | Louzai | male |
// Provided interface
public interface UserDao {
// select * from user_test where uid = "#{uid}"
public MyUser selectUserById(Integer uid);
// update user_test set uname =#{uname},usex = #{usex} where uid = #{uid}
public int updateUser(MyUser user);
}Basic test code ,testSuccess() It is the case that the transaction takes effect :
@Service
public class UserController {
@Autowired
private UserDao userDao;
public void update(Integer id) {
MyUser user = new MyUser();
user.setUid(id);
user.setUname(" Zhang San -testing");
user.setUsex(" Woman ");
userDao.updateUser(user);
}
public MyUser query(Integer id) {
MyUser user = userDao.selectUserById(id);
return user;
}
// Normal condition
@Transactional(rollbackFor = Exception.class)
public void testSuccess() throws Exception {
Integer id = 1;
MyUser user = query(id);
System.out.println(" Original record :" + user);
update(id);
throw new Exception(" Transaction effective ");
}
}There are several kinds of invalid transactions Case
Main explanation 4 Kinds of transactions do not take effect Case:
Class internal access :A Class a1 Method has no annotation @Transactional,a2 Method label @Transactional, stay a1 It calls a2;
Private method : take @Transactional Notes are marked in non public On the way ;
Abnormal mismatch :@Transactional Not set rollbackFor attribute , Method returns Exception Isoanomaly ;
Multithreading : Calling of main thread and sub thread , Thread throws an exception .
Case 1: Class internal access
We are in class UserController Add a new method testInteralCall():
public void testInteralCall() throws Exception {
testSuccess();
throw new Exception(" The transaction does not take effect : Class internal access ");
}here testInteralCall() There is no sign @Transactional, Let's take a look at the test cases again :
public static void main(String[] args) throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserController uc = (UserController) applicationContext.getBean("userController");
try {
uc.testSuccess();
} finally {
MyUser user = uc.query(1);
System.out.println(" Revised records :" + user);
}
}
// Output :
// Original record :MyUser(uid=1, uname= Zhang San , usex= Woman )
// Revised records :MyUser(uid=1, uname= Zhang San -testing, usex= Woman )As you can see from the output above , Transaction is not rolled back , What's the reason for this ?
because @Transactional The working mechanism of is based on AOP Realization ,AOP It is implemented with dynamic agent , If you call directly through a proxy testSuccess(), adopt AOP It will be enhanced before and after , The enhanced logic is actually in testSuccess() Add open before and after 、 The logic of committing transactions , The following source code will be analyzed .
Now through testInteralCall() To call testSuccess(),testSuccess() There will be no enhancement before and after , That is to say Class internal call , Will not access... Through proxy .
If it's still unclear , I recommend reading this article again , There are complete examples , Very perfect interpretation “ Class internal access ” Reasons why it cannot be enhanced before and after :https://blog.csdn.net/Ahuuua/article/details/123877835
Case 2: Private method
In private methods , add to @Transactional The note will not take effect :
@Transactional(rollbackFor = Exception.class)
private void testPirvateMethod() throws Exception {
Integer id = 1;
MyUser user = query(id);
System.out.println(" Original record :" + user);
update(id);
throw new Exception(" Test transaction validation ");
}When used directly , The following scenario is not easy to appear , because IDEA There will be reminders , The copy is : Methods annotated with '@Transactional' must be overridable, As for the deep principle , The source code part will give you interpretation .
Case 3: Abnormal mismatch
there @Transactional No settings rollbackFor = Exception.class attribute :
@Transactional
public void testExceptionNotMatch() throws Exception {
Integer id = 1;
MyUser user = query(id);
System.out.println(" Original record :" + user);
update(id);
throw new Exception(" The transaction does not take effect : Abnormal mismatch ");
} The test method : Same as Case1
// Output :
// Original record :User[uid=1,uname= Zhang San ,usex= Woman ]
// Revised records :User[uid=1,uname= Zhang San -test,usex= Woman ]@Transactional Annotations handle runtime exceptions by default , That is, only when a runtime exception is thrown , Transaction rollback will be triggered , Otherwise it doesn't roll back , As for the deep principle , The source code part will give you interpretation .
Case 4: Multithreading
Here are two different positions , One is that the child thread throws an exception , The main thread ok; One is the child thread ok, Main thread throws exception .
The parent thread threw an exception
The parent thread threw an exception , The sub thread does not throw an exception :
public void testSuccess() throws Exception {
Integer id = 1;
MyUser user = query(id);
System.out.println(" Original record :" + user);
update(id);
}
@Transactional(rollbackFor = Exception.class)
public void testMultThread() throws Exception {
new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
testSuccess();
}
}).start();
throw new Exception(" The test transaction does not take effect ");
}The parent thread throws the thread , Transaction rollback , Because sub threads exist independently , Not in the same transaction as the parent thread , Therefore, the modification of child threads will not be rolled back ,
The child thread throws an exception
The parent thread does not throw an exception , The child thread throws an exception :
public void testSuccess() throws Exception {
Integer id = 1;
MyUser user = query(id);
System.out.println(" Original record :" + user);
update(id);
throw new Exception(" The test transaction does not take effect ");
}
@Transactional(rollbackFor = Exception.class)
public void testMultThread() throws Exception {
new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
testSuccess();
}
}).start();
}Because the exception of the sub thread will not be caught by the external thread , So the parent thread does not throw exceptions , Transaction rollback did not take effect .
Source code interpretation
Now let's look at the source code , Yes @Transactional The implementation mechanism and the reason why the transaction does not take effect .
@Transactional Execution mechanism
We only look at the core logic , In code interceptorOrInterceptionAdvice Namely TransactionInterceptor Example , Participation is this object .
There is a comment in the red box , Roughly translated as “ It's an interceptor , So we just need to call : Before constructing this object , Pointcuts will be calculated statically .”

this yes ReflectiveMethodInvocation object , The member object contains UserController class 、testSuccess() Method 、 Participate in proxy objects, etc .

Get into invoke() After the method :

high energy alert !!! Here is the core logic of transactions , Including determining whether the transaction is started 、 Target method execution 、 Transaction rollback 、 Transaction submission .

private The reason why the transaction does not take effect
In the picture above , The first red box area calls the method getTransactionAttribute(), It's mainly about getting txAttr Variable , It is used to read @Transactional Configuration of , If this txAttr = null, Transaction logic will not be followed , Let's take a look at the meaning of this variable :

We go straight into getTransactionAttribute(), Focus on the method of obtaining transaction configuration .

high energy alert !!! Here is the private The reason why the transaction does not take effect ,allowPublicMethodsOnly() Keep returning false, So focus on isPublic() Method .

Next, through bit and calculation , Judge whether it is Public, The corresponding types of modifiers are as follows :
PUBLIC: 1
PRIVATE: 2
PROTECTED: 4

See here , Are you suddenly enlightened , Do you think it's very interesting ~~
Cause of abnormal mismatch
Let's go back to the core logic of transactions , Because the main method throws Exception() abnormal , Enter the logic of transaction rollback :

Get into rollbackOn() Method , Judge whether the exception can be rolled back , This needs to judge what the main method throws Exception() abnormal , Whether in @Transactional The configuration of :

We enter getDepth() Look at the exception rule matching logic , Because we're right @Transactional Configured with rollbackFor = Exception.class, So it can match successfully :

In the example winner Not for null, So I will skip the following links . But when winner = null when , That is, there is no setting rollbackFor Attribute , Will follow the default exception capture method .

high energy alert !!! Here is the reason for the abnormal mismatch , Let's take a look at the default exception capture method :

Is it suddenly clear , When there is no setting rollbackFor Attribute , Default only for RuntimeException and Error Exception execution rollback .
End
My new book 《 In depth understanding of Java The core technology 》 It's on the market , After listing, it has been ranked in Jingdong best seller list for several times , At present 6 In the discount , If you want to start, don't miss it ~ Long press the QR code to buy ~

Long press to scan code and enjoy 6 A discount
Previous recommendation
SpringBoot In production 16 Best practices
HTTP/3 Released , Let's talk about HTTP/3
There is Tao without skill , It can be done with skill ; No way with skill , Stop at surgery
Welcome to pay attention Java Road official account

Good article , I was watching ️
边栏推荐
- Seven sorts (2)
- The solution that background attribute editing cannot load after dedecms dream changes the include directory rename
- The most common algorithm interview questions
- Serein [lazy artifact] a graphical tool that collects URLs in batches and detects the collected URLs in batches. It solves the problem of fishing project
- Gao Fushui in unit testing, pytest framework (III) use case marking and test execution
- 拼多多店铺所有商品API接口(整店商品列表查询接口)
- 语音聊天源码——语音聊天源码开发设计搭建
- Basic database operations in MySQL
- 小工具(读取Excel数据并存入数据库表)
- Letter combination of leecode17 phone number
猜你喜欢

小工具(读取Excel数据并存入数据库表)

spark调优(六):大家好才是真的好——广播变量

Problems and solutions of wechat applet related knowledge points and cloud music project production

stack-protector enabled but compiler support broken

How to debug the dynamic code generated by C emit?

Seven sorts (1)
![[C language] analog address book (array version, dynamic version, linked list version)](/img/0e/ff1db5e633e8a626a1a058c5241798.png)
[C language] analog address book (array version, dynamic version, linked list version)

Using docker to build grafana+prometheus monitoring database resources (II)

微信小程序相关知识点和云音乐项目制作遇到的问题及解决

. Net webapi to realize interface version control and get through swagger support
随机推荐
系统解决方案
Enterprise naming conventions
Week 4 Data analysis algorithms-Linear models for regression-Bias-Variance Analysis(Part B)
Bool type and related operators
Suning commodity details API interface (commodity details page data interface)
Nvisual secondary development - Chapter 1 Introduction
What should investors do when the era of "lying and earning" of DFI is gone?
Today, I went to oppo for an interview and got numb...
关于DP中完全背包的遍历次序探讨
The head company of the food delivery robot has no money to burn. The official of Purdue technology announced layoffs, and the sales team cut 2/3
[introduction to C language] - pointer (elementary level)
Serein [lazy artifact] a graphical tool that collects URLs in batches and detects the collected URLs in batches. It solves the problem of fishing project
Wechat applet - Advanced chapter package JSON Version Description and detailed explanation of various version symbols (I)
关键字搜索苏宁商品API接口(苏宁商品列表API接口)
Interviewer: how to clean the data of ES cluster regularly
Gadget (read Excel data and save it into database table)
Byte encountered a wave of resignation!
mysql库使用中卡死或者死锁事件
Go language pointer
How to debug the dynamic code generated by C emit?


