Under Spring, the discussion about the transaction problem of dynamic data source

Happy moment

  Venomous snakes and pythons are discussing who the most efficient way of hunting.

  Viper: I only need to bite each other, and over time, it will gradually lose its ability to move and eventually die.

  Python sneered: That has to wait for the effective time, I just need to entangle the other party, it can immediately kill it.

  The viper is furious: you are entangled in it, you are cheap!

  Python: Didn't you kiss it too?

Review

Looking at the title of the article, I don't know if you can think of what the specific problem is. If you are a little ignorant, that's right! (If you are not ignorant, this article will not be meaningful, hehe)

Before pointing out what the specific problem is, let ’s review some content first

  Spring transaction principle

  I believe everyone can say something about this. Spring transactions are a specific application of Spring AOP. The bottom layer depends on dynamic proxies.

  The general process is similar to the following

    

  Call the target object through the proxy object, and there are transaction-related enhanced processing in the proxy object

  For specific details, please refer to the following article      

    Spring transaction source code analysis

    Take a look at the Spring transaction source code in combination with ThreadLocal and feel the clean spring!

    Remember an online question → Where did the business go

  Spring dynamic data source principle

  Principle decryption → Spring AOP implements dynamic data sources (read and write separation). The underlying principles have been introduced in detail. The process is roughly as follows

    

  Spring AOP → put our specified lookupKey into ThreadLocal

  ThreadLocal → shared lookupKey within the thread

  DynamicDataSource → encapsulate multiple data sources, and dynamically select specific data sources based on the lookupKey in ThreadLocal

What's the problem

Since transactions and dynamic data sources are specific applications of Spring AOP, there is a sequence of proxies

Either

Either

Let's see what is the difference between the two

  Transaction first, dynamic data source last

  At this time, the pre-enhanced processing of the transaction will be effective, so where does the Connection that started the transaction come from? It must be from DynamicDataSource, because it is what we configure for the transaction manager

    @Bean
     public PlatformTransactionManager transactionManager (@Qualifier ("dynamicDataSource" ) DataSource dynamicDataSource) {
         // Configure transaction management, add @Transactional annotation to the method header when using transactions to 
        return  new DataSourceTransactionManager (dynamicDataSource); 
    }

  Since it is a Connection obtained from DynamicDataSource, when DynamicDataSource obtains Connection according to lookupKey, will it be obtained from masterDataSource data source or slaveDataSource data source? Because the lookupKey has not been bound to the current thread at this time, the DynamicDataSource will be obtained from the default data source, and the default data source we configured is slaveDataSource

    / ** 
     * Get the data source of the current thread 
     * @return 
     * / 
    public  static DataSourceType getDataSourceType () 
    { 
        return   HOLDER.get () == null ? DataSourceType.SLAVE: HOLDER.get (); 
    }

  To put it bluntly, the dynamic data source does not take effect on the transaction at this time, and the transaction always obtains the Connection from the default data source without dynamic effects.

  Talk is cheap. Show me the code, let ’s see if it ’s really as above

  

   192.168.0.112  is our slave library, corresponding to our default data source slaveDataSource 

  Dynamic data source first, transaction last

  At this time, the pre-enhancement of the dynamic data source will be executed first, and the lookupKey required by the DynamicDataSource will be bound to the current thread before the transaction. Then when the transaction obtains the Connection from the DynamicDataSource, it can dynamically select masterDataSource or slaveDataSource according to the lookupKey of the current thread

  There is no problem in this case

Solve the problem

Summarize the question: how to ensure that the dynamic data source in the transaction also has a dynamic effect, that is, how to ensure that the pre-enhancement of the dynamic data source precedes the transaction

We know that Spring AOP can specify the order, as long as we display the AOP that specifies the dynamic data source before the AOP of the transaction; how to specify the order, the common way is to implement the Order interface, or use @Order annotation, the order value Smaller, the first to execute, so we only need to ensure that the Order value of the dynamic data source is less than the Order value of the transaction

Let ’s first take a look at the default value of the Order of the transaction, in the EnableTransactionManagement annotation

    /**
     * Indicate the ordering of the execution of the transaction advisor
     * when multiple advices are applied at a specific joinpoint.
     * <p>The default is {@link Ordered#LOWEST_PRECEDENCE}.
     */
    int order() default Ordered.LOWEST_PRECEDENCE;

The default is the lowest level (the value is very large), then we only need to ensure that the Order of the dynamic data source is smaller than this value, we take 1

  @Component
  @Slf4j
  @Order(1)
  public class DynamicDataSourceAspect {

We are here to see if it is really feasible

It is no longer the default slaveDataSource, but the masterDataSource we specified (specified by @MasterSlave (MASTER))

At this point, I believe you have figured out what the problem is and how to solve it

What, don't you understand? Come here, I promise not to kill you

to sum up

1. Not only dynamic data sources and transactions, as long as multiple AOPs are involved, there may be a sequence problem, which is worth everyone's attention

2. Related constraints

  The master database performs INSERT UPDATE DELETE operations, and there may be some SELECT operations (the master-slave synchronization has a delay)

  Perform only SELECT operations from the database

  The default data source is best set as the master data source to prevent careless execution of the update operation to the slave database; the reason why the landlord is set as the slave data source is to consider that most database operations are queries, which can reduce the amount of code; how to choose , You need to decide based on the actual situation

Guess you like

Origin www.cnblogs.com/youzhibing/p/12671004.html