An overview of the

In the case of a single machine, we would encounter similar situations, such as locking when multiple threads need to access a shared resource. In Java, an easy way to do this is to use the synchronized keyword to lock a method or variable. However, this locking mode in the process of sharing appears to be inadequate. To solve this problem, we must introduce distributed locks. Distributed locks are generally used to access mutually exclusive resources. Here, we will use the MySQL database to implement distributed locks. Of course, there are other ways to achieve distributed lock, such as redis, ZooKeeper, etc., these ways can be very convenient to find the implementation scheme on the Internet. For performance, use cache (Redis) > Zookeeper > MySQL database. Redis can implement distributed locks, of course, but in the case of low QPS, using such distributed locks introduces complexity. Use MySQL database for fast development. In many cases, the advanced solution does not bring more benefits than the old solution, in which case the simple solution is also a good solution.

A scheme based on Optimistic Locking (CAS)

As the name implies, optimistic locks do not conflict in most cases and are used to ensure performance without collisions. In fact, optimistic locking is not a lock, so it saves the time and resource consumption associated with locking and releasing locks. At the same time, the lockless mechanism naturally avoids deadlocks. Optimistic locking is actually an idea: Compare and swap (CAS), which simply means THAT I will only swap when the data is the original data. The following Java code can explain this operation.

public boolean cas(int addr, int oldValue, int newValue) {
    if(addr ! = oldValue)return false;
    addr = newValue;
    return true;
}
Copy the code

Where addr refers to the data to be modified, oldValue refers to the data before the modification, and newValue refers to the data to be modified. When two processes perform a modification, only one of them will take effect and return true, while the other will fail and return false. Note that a CAS operation must be atomic, otherwise it will not work properly.

ABA problem

The problem can be simplified to the following sequence diagram

The sequential The value of the target Process 1 The other processes
1 0 Read 0
2 0 Read 0
3 1 Change to 1
4 0 Modified to 0
5 1 Change to 1

If you notice that other processes change the data to 1 and then back to 0, process 1 will assume that no changes have been made and will perform subsequent operations, which may cause some problems. To solve this problem, consider adding a version number above the field. Each change requires a comparison of the version number and a +1 version number for successful changes. You can also use timestamps to do the same thing.

The specific implementation

The database can build the table test_table like this

Name Type Not null Comment
id int Square root The id, the only
value int The value to be modified
update_time int Update time

When using optimistic locks, you need to ensure that there is data in the database before it can be updated.

UPDATE
    test_table
SET
    value = #{ value },
    update_time = #{ newUpdateTime }
WHERE
    id = #{ id }
    AND update_time = #{ oldUpdateTime }
Copy the code

Since mysql update returns the number of rows updated, you only need to check whether the value returned is 1. If the value is 0, you need to retrieve the data in the database again and update it again. Note that you need to set a limit on the number of cycles, otherwise it may lead to an infinite loop.