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