preface
Recent chat with friends, he said that he met in outsourcing projects, distributed transaction problem, ask I have no solution, I could talk to him directly, distributed transaction scheme online a lot of, what TCC and reliable message consistency, best to inform, direct online to find a try, such as direct use ali seata. But I didn’t do that, because distributed transactions are a very complex topic, and when it comes down to it, sometimes multiple distributed solutions are used together, rather than one solution going dark.
Therefore, I told him that if it is possible to avoid distributed transactions, try not to use them. Then I asked him about his business scenario, which was not very complicated. It was to invite friends to register and then increase points
@Transactional(rollbackFor = Exception.class)
public Boolean inviteUser(..){ userService.add(..) ; integralService.addIntegration(.. .20)}Copy the code
IntegralService is a remote integralService, and 20 is the increased integral value. This code appears to be fine at first glance, and I think many of my friends would write this. Later, I asked my friend whether the following scenarios are allowed in your business scenario
- Do you allow the invited user to enter the library successfully, but the integral fails?
- Does the invited user fail to log in, but the integral log in succeeds?
The friend thought for a while and said the second way is not allowed. The first way can increase the integral through compensation.
Now let’s go back to the code and ask the following two questions for those of you reading this article
- Is there a problem with this code if it takes too long to add credit requests?
- If adding integral is abnormal due to network jitter, is there a problem with this code?
Here’s what I think
- If the time is too long, long transactions may occur. In concurrent scenarios, database connections may not be released
- If network jitter is abnormal, the adding logic of the user service may be rolled back
If it takes too long to solve the problem, some friends may think of adopting the asynchronous way. If the integral jitter is abnormal, they can add the circuit breaker mechanism. For example, if there is no response after the integral time expires, they can directly fuse
Today I will say another solution, is to call after the transaction is committed, Rory it wordy a lot of, just to get into the topic, ha ha
How to make a remote call correctly in a Spring transaction
Through Spring’s transaction synchronization manager
What is this ghost, this is my literal translation, its real body is as follows
org.springframework.transaction.support.TransactionSynchronizationManager
Copy the code
If this thing is useful, you can use it to register a transaction synchronizer, which allows you to do something after a transaction has committed. The core code is as follows
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit(a) {
// Do what you want to do}});Copy the code
So if you look at the code, you all know how to modify the invitation to add credits
@Transactional(rollbackFor = Exception.class)
public Boolean inviteUser(..) { userService.add(..) ; TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit(a) { integralService.addIntegration(.. .20)}});Copy the code
But we found no, every time to write such a pile of code, looking at whether it is very disgusting, there is no transformation plan. The answer is yes, through annotation + AOP to integrate the implementation, specific implementation logic, you can see the following demo link
com.github.lybgeek.transactional
Copy the code
I’m not going to post the code here, but why not, because I’m going to introduce another solution, which is an event-driven implementation based on Spring
Through TransactionalEventListener annotations + ApplicationEventPublisher
This is spring event driven, or the observer is implemented, but TransactionalEventListener annotations are spring4.2 version before provide annotations
In this way, how to modify the above implementation of inviting users to add credits?
1. In the invite user registration method, publish the event
The pseudocode is as follows
@Transactional(rollbackFor = Exception.class)
public Boolean inviteUser(..) { userService.add(..) ; applicationEventPublisher.publishEvent(..) ; });Copy the code
2. Write a transaction listener that triggers the addition of integral implementations
The pseudocode is as follows
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void addIntegration(..){ integralService.addIntegration(.. .20)}Copy the code
One detail to note here is that the parameters of the listening event must be the same as the published parameters
3, realize the core source code
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronization transactionSynchronization = createTransactionSynchronization(event);
TransactionSynchronizationManager.registerSynchronization(transactionSynchronization);
}
else if (this.annotation.fallbackExecution()) {
if (this.annotation.phase() == TransactionPhase.AFTER_ROLLBACK && logger.isWarnEnabled()) {
logger.warn("Processing " + event + " as a fallback execution on AFTER_ROLLBACK phase");
}
processEvent(event);
}
else {
// No transactional event execution at all
if (logger.isDebugEnabled()) {
logger.debug("No transaction is active - skipping "+ event); }}}Copy the code
Don’t know you found no, he is essentially used TransactionSynchronizationManager, just encapsulate again for him
conclusion
After communicate with friends, find their the outsourcing project developers, and there were only three, and then a split for 10 to service, I asked him the outsourcing business is very complicated, he said it’s good, I ask he says business is not complicated, developers also not much, why not use monomer architecture, and want to use service. The answer he gave me was that the father of party A thought that their project would carry a large amount of business in the future, so they had to use micro services, and the mainstream technology stack is micro services. Should I say over-design or over-thinking? Technology is changing fast, and who knows what’s going to happen next? Architecture is never a one-step thing, it’s a gradual evolution
The demo link
Github.com/lyb-geek/sp…