SoFunction
Updated on 2025-05-21

Common causes and solutions for MyBatis-Plus optimistic lock failure

Preface

In high concurrency scenarios, optimistic locking is the core tool to ensure data consistency. As the leader of the Java ORM framework, MyBatis-Plus provides developers with elegant and optimistic lock implementations through @Version annotation and OptimisticLockerInnerInterceptor plug-in. However, developers often encounter the problem of optimistic locking "not taking effect" in actual use.

1. The core principle of optimistic locking

1. What is optimistic lock?

Optimistic locking is a concurrency control strategy that assumes that "conflicts rarely occur" (optimistic locking assumes that most operations will not conflict and only checks the data version when updated. If the version matches, the update will be successful; otherwise, an exception will be thrown). The core idea is:

  • When reading data: Record the current version number (such asversionfield).
  • When updating data: Verify whether the version number matches. If it matches, the update is successful and the version number is incremented; otherwise, an exception is thrown (such asOptimisticLockException)。

2. The implementation mechanism of MyBatis-Plus

MyBatis-Plus achieves optimistic locking through the following three steps:

  • Entity class annotation @Version annotation: marks the version number field.
  • Configure the OptimisticLockerInnerInterceptor plug-in: Intercept SQL and automatically process version number conditions.
  • Automatically verify the version number during update operation: generate SQL similar to UPDATE ... WHERE version = ?.

2. Common reasons for the failure of optimistic locks

1. The plugin is not configured correctly

question: Not registeredOptimisticLockerInnerInterceptorPlugin, causing MyBatis-Plus to not automatically process version number logic.

Sample code

@Configuration
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // Optimistic lock plugin must be added        (new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

2. Entity class field is not marked @Version

question: Not used in entity class@VersionNote, MyBatis-Plus cannot recognize the version number field.

Sample code

import ;

public class User {
    // Correctly label the version number field    @Version
    private Integer version;

    // Other fields...}

3. Database fields are not initialized

question: Database tableversionThe field isNULLOr the default value is not set, resulting in the inability to compare version numbers during the first update.

Solution

-- make sure version The field has an initial value
ALTER TABLE user ADD COLUMN version INT NOT NULL DEFAULT 1;

4. The update operation is not based on the query data

question: Directly construct new object updates, and the version number in the database is not read, resulting in the optimistic lock failure.

Sample code

// Error method: directly construct new objectUser user = new User();
(1L);
("New Name");
(user); // version not passed, optimistic lock fails
// Correct way: query the data firstUser user = (1L); // Query the current data (including version)("New Name");
(user); // Automatic processing version increment

5. Custom SQL does not include version number conditions

question: Not explicitly added when using custom SQL updateversionConditions lead to the failure of optimistic lock plug-in.

Solution

<!-- The correct way:Explicitly added version condition -->
<update >
    UPDATE user
    SET name = #{name}, version = version + 1
    WHERE id = #{id} AND version = #{version}
</update>

6. The transaction is not started correctly

question: Optimistic locking depends on the atomicity of the transaction. If the transaction is not enabled, it may cause the version number to be updated.

Sample code

@Transactional
public void updateData(Long id, String newName) {
    User user = (id); // Query data    (newName);
    (user); // The version number is incremented after the transaction is committed}

7. Concurrent tests did not trigger conflict

question: The concurrent scenario is not simulated, and the verification effect of optimistic lock cannot be observed.

Test code

@Test
public void testOptimisticLock() {
    User user1 = (1L); // version=1
    User user2 = (1L); // version=1

    ("Thread 1");
    (user1); // version becomes 2
    ("Thread 2");
    try {
        (user2); // OptimisticLockException should be thrown here    } catch (OptimisticLockException e) {
        ("Optimistic lock takes effect, update failed");
    }
}

8. Version field type mismatch

question@VersionThe types supported by annotations areInteger/Long/Date/Timestamp/LocalDateTime, if using other types (such asString), which will cause the optimistic lock to fail.

Sample code

// Correct type@Version
private Integer version; // or Long/LocalDateTime
// Error type@Version
private String version; // Type mismatch, optimistic lock fails

9. MyBatis-Plus version is too low

question: Older versions may have bugs or feature limitations.
Solution: Upgrade to the latest version (recommended3.5.7+)。

<dependency>
    <groupId></groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.7</version>
</dependency>

3. Complete solution example

1. Database table design

CREATE TABLE user (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    version INT NOT NULL DEFAULT 1 -- Initialize version number
);

2. Entity class configuration

import .*;

@TableName("user")
public class User {
    @TableId(type = )
    private Long id;

    private String name;

    @Version
    private Integer version; // Version number field
    // Getter &amp; Setter
}

3. Configure plug-in

@Configuration
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        (new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

4. Business logic code

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Transactional
    public void updateUser(Long id, String newName) {
        User user = (id); // Query the current data        (newName);
        int result = (user); // Automatic version processing        if (result == 0) {
            throw new OptimisticLockException("Optimistic lock update failed");
        }
    }
}

4. Advanced skills and precautions

1. Custom version number field name

If the database field name is inconsistent with the entity class field name, you can use@TableIdor@TableFieldSpecify the mapping:

@TableField("ver")
@Version
private Integer version;

2. Verification of version number for multi-condition updates

In complex update scenarios, the version number logic needs to be processed manually:

UpdateWrapper<User> wrapper = new UpdateWrapper<>();
("id", 1L).eq("version", ());
(() + 1);
(user, wrapper);

3. Version number consistency in distributed environments

In a distributed system, ensure that all nodes share the same database and avoid version number conflicts. If you need to synchronize across nodes, you can combine Redis or database middleware to implement it.

4. Performance optimization suggestions

  • Reduce transaction scope: Only start transactions when necessary to avoid long transactions affecting concurrency performance.
  • Batch update version number processing: For batch operations, you need to verify the version number one by one, or use sharding strategy.

5. Summary

The essence of MyBatis-Plus' optimistic locking mechanism is to "ensure data consistency through version number comparison", but its effectiveness depends on the correct configuration and implementation of multiple links. Here is a review of key points:

Key points illustrate
Plug-in configuration Must registerOptimisticLockerInnerInterceptor
Entity class annotation use@VersionLabel version number field
Database initialization versionThe field must have a non-null initial value
Update logic Based on the query data update, avoid direct construction of new objects
Custom SQL Explicitly addedversioncondition
Transaction Management use@TransactionalEnsure transaction consistency
Concurrent testing Simulate multi-threaded scene verification optimistic locking effect
Field type and version compatibility Make sure the field type isInteger/Long/LocalDateTime, upgrade MyBatis-Plus to the latest version

Official DocumentMyBatis-Plus Optimistic Lock Guide

The above is the detailed content of the common causes and solutions for the failure of MyBatis-Plus optimistic lock. For more information about the failure of MyBatis-Plus optimistic lock, please pay attention to my other related articles!