Hello everyone, I'm Glacier~~
In daily work, if Spring's transaction management function is used improperly, it will cause the problem that Spring transactions do not take effect. The problem that Spring transactions do not take effect is also a question that is frequently asked in job-hopping interviews.
Today, let's sort out which scenarios will cause Spring transactions to take effect.
Note: Part of the content is quoted from the book "In -depth Understanding of Distributed Transactions: Principles and Practice " published by Glacier and Cat .
Articles are included on GitHub and Gitee:
GitHub: https://github.com/sunshinelyz/technology-binghe
Gitee: https://gitee.com/binghe001/technology-binghe
Overview of Spring transactions not taking effect
In short, Spring transactions fail in several specific scenarios, as shown in the following figure.
The database does not support transactions
The prerequisite for Spring transactions to take effect is that the connected database supports transactions. If the underlying database does not support transactions, Spring transactions will definitely fail. For example, if the database used is MySQL and the MyISAM storage engine is selected, Spring's transactions will fail.
Transaction methods are not managed by Spring
If the class in which the transaction method is located is not loaded into the Spring IOC container, that is, the class in which the transaction method is located is not managed by Spring, the Spring transaction will fail. The example is as follows.
public class ProductService {
@Autowired
private ProductDao productDao;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateProductStockCountById(Integer stockCount, Long id){
productDao.updateProductStockCountById(stockCount, id);
}
}
There is no @Service annotation on the ProductService class, and the instance of Product is not loaded into the Spring IOC container, which will cause the transaction of the updateProductStockCountById() method to fail in Spring.
The method is not modified by public
If the method in which the transaction is located is not modified by public, then Spring's transaction will be invalid, for example, as shown in the following code.
@Service
public class ProductService {
@Autowired
private ProductDao productDao;
@Transactional(propagation = Propagation.REQUIRES_NEW)
private void updateProductStockCountById(Integer stockCount, Long id){
productDao.updateProductStockCountById(stockCount, id);
}
}
Although the ProductService is marked with the @Service annotation, the updateProductStockCountById() method is marked with the @Transactional(propagation = Propagation.REQUIRES_NEW) annotation.
However, since the updateProductStockCountById() method is an internal private method (modified with private), the transaction of the updateProductStockCountById() method will be invalid in Spring at this time.
Method calls in the same class
If the two methods in the same class are A and B, the transaction annotation is not added to method A, the @Transactional transaction annotation is added to method B, and method A calls method B, the transaction of method B will be invalid. For example, as shown in the following code.
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private ProductDao productDao;
public void submitOrder(){
//生成订单
Order order = new Order();
long number = Math.abs(new Random().nextInt(500));
order.setId(number);
order.setOrderNo("order_" + number);
orderDao.saveOrder(order);
//减库存
this.updateProductStockCountById(1, 1L);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateProductStockCountById(Integer stockCount, Long id){
productDao.updateProductStockCountById(stockCount, id);
}
}
The submitOrder() method and the updateProductStockCountById() method are both in the OrderService class. The submitOrder() method is not marked with transaction annotations, and the updateProductStockCountById() method is marked with transaction annotations. The submitOrder() method calls the updateProductStockCountById() method. At this time, updateProductStockCountById () method transactions are invalidated in Spring.
Transaction manager not configured
If Spring's transaction manager is not configured in the project, even if Spring's transaction management function is used, Spring's transaction will not take effect.
For example, the following code is not configured in the configuration class of the project.
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
At this point, Spring's transaction will be invalid.
The transaction propagation type of the method does not support transactions
If the transaction propagation type of the inner method is a propagation type that does not support transactions, the transaction of the inner method will be invalid in Spring.
For example, as shown in the following code.
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private ProductDao productDao;
@Transactional(propagation = Propagation.REQUIRED)
public void submitOrder(){
//生成订单
Order order = new Order();
long number = Math.abs(new Random().nextInt(500));
order.setId(number);
order.setOrderNo("order_" + number);
orderDao.saveOrder(order);
//减库存
this.updateProductStockCountById(1, 1L);
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void updateProductStockCountById(Integer stockCount, Long id){
productDao.updateProductStockCountById(stockCount, id);
}
}
Since the transaction propagation type of the updateProductStockCountById() method is NOT_SUPPORTED and does not support transactions, the transaction of the updateProductStockCountById() method will be invalid in Spring.
Incorrectly caught exception
Incorrectly caught exceptions can also cause Spring's transactions to fail, as shown below.
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private ProductDao productDao;
@Transactional(propagation = Propagation.REQUIRED)
public void submitOrder(){
//生成订单
Order order = new Order();
long number = Math.abs(new Random().nextInt(500));
order.setId(number);
order.setOrderNo("order_" + number);
orderDao.saveOrder(order);
//减库存
this.updateProductStockCountById(1, 1L);
}
@Transactional(propagation = Propagation.REQUIRED)
public void updateProductStockCountById(Integer stockCount, Long id){
try{
productDao.updateProductStockCountById(stockCount, id);
int i = 1 / 0;
}catch(Exception e){
logger.error("扣减库存异常:", e.getMesaage());
}
}
}
The try-catch code block is used in the updateProductStockCountById() method to catch the exception. Even if an exception is thrown inside the updateProductStockCountById() method, it will be caught by the catch code block. At this time, the transaction of the updateProductStockCountById() method will be committed without returning Rollback, and the transaction of the submitOrder() method will be committed but not rolled back, which causes the rollback failure of Spring transactions.
Wrong annotation exception type
If the wrong exception type is marked in the @Transactional annotation, the rollback of the Spring transaction will be invalid. The example is as follows.
@Transactional(propagation = Propagation.REQUIRED)
public void updateProductStockCountById(Integer stockCount, Long id){
try{
productDao.updateProductStockCountById(stockCount, id);
}catch(Exception e){
logger.error("扣减库存异常:", e.getMesaage());
throw new Exception("扣减库存异常");
}
}
The exception is caught in the updateProductStockCountById() method, and an exception of type Exception is thrown in the exception. At this time, the transaction rollback of the updateProductStockCountById() method will be invalid.
Why does it fail? This is because the transaction exception type for the default rollback in Spring is RuntimeException, and the above code throws an Exception exception.
By default, the Exception exception cannot be caught in the Spring transaction, so the rollback of the transaction in the updateProductStockCountById() method will be invalid.
At this point, you can manually specify the transaction exception type marked by the updateProductStockCountById() method, as shown below.
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
Here, it should be noted that the rollbackFor attribute in the Spring transaction annotation @Transactional can specify the Throwable exception class and its subclasses.
Okay, let's stop here today, I'm Glacier, see you next time~~
write at the end
If you want to enter a big factory, want to get a promotion and a salary increase, or are confused about your current job, you can privately message me to communicate, I hope some of my experiences can help you~~
Recommended reading:
- " Practice brings true knowledge: Deciphering the architecture of the strongest seckill system in the entire network, not all seckills are seckills! ! 》
- " From zero to hundreds of millions of users, how do I optimize MySQL database step by step? (recommended collection)》
- " I used multi-threading to further optimize the massive data proofreading system under the billion-level traffic e-commerce business, and the performance has been improved by 200%! ! (The whole process is dry, it is recommended to collect)》
- " I used multi-threading to optimize the massive data proofreading system under the billion-level traffic e-commerce business, and the performance was directly improved by 200%! ! (The whole process is dry, it is recommended to collect)》
- " I summed up the best learning route for concurrent programming with 10 pictures! ! (recommended collection)》
- " A lock that is faster than read-write locks in high concurrency scenarios, I am completely convinced after reading it! ! (recommended collection)》
- " Summary of the most complete performance optimization of the entire network! ! (Glacier Hematemesis Arrangement, Recommended Collection)》
- " After three days of playing MyBatis, feel free to ask! ! (Glacier Hematemesis Arrangement, Recommended Collection)》
- " Advice to those who have just started working: If you want to enter a big factory, you must master these concurrent programming knowledge! Complete Learning Route! ! (recommended collection)》
- " Advice to those juniors and juniors who have just started working: If you want to enter a big factory, you must master these core skills! Complete Learning Route! ! (recommended collection)》
- " Advice to those who have just started working: The sooner you know the basics of these computers and operating systems, the better! The 10,000-character long text is too top! ! (recommended collection)》
- " I developed a national-level game suitable for all ages in three days, supports playing music, and now open the complete source code and comments (recommended collection)! ! 》
- " I am the most hard-core high-concurrency programming author on the entire network, and the most noteworthy blogger on CSDN, do you agree? (recommended collection)》
- " Five years after graduation, from a monthly salary of 3,000 to an annual salary of one million, what core skills have I mastered? (recommended collection)》
- " I hacked into the Wifi of the girl next door and found out. . . (The whole process of actual combat dry goods, it is recommended to collect) "
- " Don't try "Panda Burning Incense" lightly, no, I regret it! 》
- " Tomb-sweeping Day secretly trained "Panda Burning Incense", and my computer "dedicated" to panda! 》
- " 730,000 words bursting with new features of Java8, I don't believe you can read it! (recommended collection)》
- " What's it like to unplug your server during peak business hours? 》
- " Summary of the most complete Linux commands on the entire network! ! (The most complete in history, recommended collection) "
- " Wrote a tool in Python, perfectly cracked MySQL! ! (recommended collection)》
- Why is the SimpleDateFormat class not thread-safe? (with six solutions, recommended collection) "
- " These three new indexes in MySQL 8 have directly let MySQL take off, you don't even know it! ! (recommended collection)》
- " After finishing the Spring source code, I open sourced this distributed cache framework! ! (recommended collection)》
- "The product of the 100 million-level traffic high concurrent spike system is "oversold", just because there are these two huge pits in the JDK synchronization container used! ! (The record of stepping on the pit, it is recommended to collect) "
- " Advise those who have just started working: If you want to learn concurrent programming well, you must pay attention to the pits of these concurrent containers! ! (recommended collection)》
- "The company's reporting tool is too difficult to use. I picked up an Excel tool in three days. The operation lady said it was very easy to use, and it is now open source! ! (recommended collection)》
- " Advice to those who have just started working: If you want to enter a big factory, these core skills of concurrent programming are what you must master! ! (recommended collection)》
- " Ali Interviewer: How does the high-concurrency and high-traffic spike system correctly solve the problem of oversold inventory? (recommended collection)》
- " Redis five data types and usage scenarios summary! ! (including complete actual combat cases, it is recommended to collect)》
Okay, let's stop here today, friends, like, favorite, comment, and start walking with one click, I'm Glacier, see you in the next issue~~