A few days ago I posted an article with a question about transaction failures:
What are the scenarios where controlling transactions with Spring’s @bigflash annotation doesn’t work?
One of the enthusiastic fans left a message to share, I think summed up a little experience, to the top:
However, I think the summary is not complete enough. Today, I will summarize again, and then add and improve the summary of this fan. Needless to say, I will not summarize all, but I hope to help those in need.
The database engine does not support transactions
Here take MySQL as an example, its MyISAM engine does not support transaction operations, InnoDB is the engine that supports transactions, generally to support transactions will use InnoDB.
According to the official MySQL documentation:
https://dev.mysql.com/doc/refman/5.5/en/storage-engine-setting.html
The default storage engine since MySQL 5.5.5 is InnoDB. The default storage engine before MySQL 5.5.5 is MyISAM, so it is worth noting that the underlying engine does not support transactions.
2. Not managed by Spring
As shown in the following example:
If you comment out the @service annotation at this point, the class will not be loaded as a Bean, the class will not be managed by Spring, and the transaction will be invalidated.
3. Methods are not public
The following is from the Official Spring documentation:
When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.
Transactional methods can only be used for public methods, otherwise transactions will not fail. To use a non-public method, turn on the AspectJ proxy mode.
4. Self call problem
Take a look at two examples:
//@Service
publicclassOrderServiceImplimplementsOrderService{
@Transactional
publicvoidupdateOrder(Orderorder){
try{
//updateorder
}catch{
thrownewException("Update error"); }}}Copy the code
Call the @Transactional updateOrder method without the Transactional annotation. Do transactions on the updateOrder method work?
Consider the following example:
@Service
publicclassOrderServiceImplimplementsOrderService{
@Transactional
publicvoidupdate(Orderorder){
updateOrder(order);
}
@Transactional(propagation=Propagation.REQUIRES_NEW)
publicvoidupdateOrder(Orderorder){
//updateorder
}
}Copy the code
“Transactional” (@transactional); “REQUIRES_NEW” (updateOrder);
The answer in both cases is: It doesn’t work!
Calling the class’s own methods because they are called by themselves, while not going through Spring’s proxy classes, by default, only invoke transactions from outside the class, is a classic cliche.
One of the solutions to this is to inject itself into the class and then call another method with the injected object. This is not very elegant. Another possible solution is to see how Spring can start a Transaction in one Transaction? This article.
The data source is not configured with a transaction manager
@Bean
publicPlatformTransactionManagertransactionManager(DataSourcedataSource){
returnnewDataSourceTransactionManager(dataSource);
}Copy the code
As shown above, if the current data source is not configured with a transaction manager, it is useless!
6. Transactions are not supported
Consider the following example:
@Service
publicclassOrderServiceImplimplementsOrderService{
@Transactional
publicvoidupdate(Orderorder){
updateOrder(order);
}
@Transactional(propagation=Propagation.NOT_SUPPORTED)
publicvoidupdateOrder(Orderorder){
//updateorder
}
}Copy the code
Propagation.NOT_SUPPORTED: Indicates that no transaction is run. If a transaction exists, it is suspended
Do not actively support the transaction mode to run, that transaction is useless!
Abnormality is eaten
This is also the scene that appears more frequently:
//@Service
publicclassOrderServiceImplimplementsOrderService{
@Transactional
publicvoidupdateOrder(Orderorder){
try{
//updateorder
}catch{
}
}
}Copy the code
Eat abnormal, and then do not throw out, business how to roll back!
8. The exception type is wrong
The above example throws another exception:
//@Service
publicclassOrderServiceImplimplementsOrderService{
@Transactional
publicvoidupdateOrder(Orderorder){
try{
//updateorder
}catch{
thrownewException("Update error"); }}}Copy the code
This transaction also does not take effect, because the default rollback is RuntimeException. If you want to trigger the rollback of other exceptions, you need to configure this in the annotation, such as:
@Transactional(rollbackFor=Exception.class)Copy the code
This configuration is limited to Throwable exception classes and their subclasses.
conclusion
This article summarizes eight transaction failure scenarios, but the most common ones are self-invocation, exception eating, and exception throwing of the wrong type.
As stated at the beginning of this article, this is not necessarily a complete summary, but just a summary of common transaction failure scenarios. Even so, these 8 tips should be enough to make your interview easier. If you know of any other scenarios, please share them in the comments.
Like to come to a small attention, small private letter micro you can get free relevant information oh