The JPA-update method uses the pit record

JPA stepping problem

Recently, JPA was used in the project. When using JPA, there was a problem due to negligence, or it was caused by unfamiliarity with JPA. The problem is this:

Let me summarize the cause of the problem:
In method A, the date field of the order table (order) of the database is updated, but when the transaction has not been submitted, the mq message is received, and the status field status of the order table is updated. But because the A method has not yet committed the transaction, the mq method of updating the status field will overwrite the date update information in the A method, and overwrite the date with the value before the A method is updated.

Insert picture description here
Here I explain the meaning of the timing diagram:

  1. System A is the system I am responsible for, and system B is my downstream. After the customer’s appointment time, I will first save the customer’s appointment time in the order table of the database. This is the first step in the sequence diagram.
  2. Step 2: This time will be synchronized to the downstream, here is a simple dubbo interface call
  3. In the third step, I will continue to deal with some other logic here, but there is a problem: the three steps 1, 2, and 3 are in the same transaction. In this case, only when 1, 2, and 3 are all completed, Will commit the transaction and update the time to the order table in the database
  4. But in step 2, after calling the downstream interface, the downstream will send an mq message back to notify my A system to make a status change, that is, the updateStatus method. The status here is not the status of my own order, but A downstream business status (X field), but also in the order table, so after receiving the message in step 4, I will query the order table according to the order id
  5. The fifth step is to update the value of the X field; the problem is here: in the fifth step, for the convenience of the diagram, I called the JPA
org.springframework.data.repository.CrudRepository#save

This save method is to insert if the record does not exist, and execute update if the record exists;

So where is the problem?

  1. When the updateDate method transaction has not yet been committed, the downstream mq message is received
  2. When receiving the message, query the database according to the primary key ID and get the order record. At this time, the time field of the order record is still null because the updateDate transaction has not yet been submitted
  3. Then when the logic processing is performed in step 5, updateDate commits the transaction, but before the transaction is submitted, the updateStatus method has already queried the database, and the obtained date is null, so when updateStatus updates the status, directly put the date field Update to null

Therefore, the problem lies in:
1. When the transaction of method A has not been submitted, method B queried the data from the database, but the 2.
method B used to update all fields before the transaction of A was submitted, and the transaction was submitted in B Previously, transaction A was submitted
3. When method B is updated, the updated fields of transaction A will be overwritten

Solution

At that time, because of the eagerness to publish online, I temporarily replaced the save method of jpa called in updateStatus with local sql to write, that is

@Query(value = "update order  set status = :status where id = :id",nativeQuery = true)
@Modifying

Through local sql, only update the fields that need to be updated in this method

The second method:
I later considered it. I can consider reducing the scope of the transaction in the updateDate method. After 1 and 2 are executed, the transaction is submitted. As for the other logic in the third step, if there is an error, it will only Roll back the third step. When the customer makes an appointment again, the time that the last appointment failed will be overwritten
, and there is still a certain risk in the use of large transaction methods.

to sum up

In summary, it is one sentence: For unfamiliar technologies, be cautious. If you don’t understand the characteristics of a framework, try to control the execution of the method yourself. This way, you can at least ensure the stability of the system. Refactor business logic and code

Guess you like

Origin blog.csdn.net/CPLASF_/article/details/108035943