解决方法:

使用悲观锁,通过数据库的锁机制来保证并发更新同一行数据时的数据一致性。具体实现可以使用MyBatis-Plus提供的selectForUpdate方法来加锁。

完整代码:

首先,在pom.xml中添加以下依赖:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.1.1</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

在application.yml中配置数据源:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false
    username: root
    password: root

创建一个实体类User:

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

    private String name;

    private Integer age;

    @Version
    private Integer version;
}

创建一个UserMapper接口:

public interface UserMapper extends BaseMapper<User> {
    @Select("select * from user where id = #{id} for update")
    User selectByIdForUpdate(Long id);
}

在UserService中实现更新操作:

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Transactional
    public void update() throws InterruptedException {
        User user = userMapper.selectByIdForUpdate(1L); // 加锁
        System.out.println("Thread " + Thread.currentThread().getName() + " read data: " + user);
        user.setAge(user.getAge() + 1);
        Thread.sleep(5000); // 模拟业务处理时间
        userMapper.updateById(user);
    }
}

编写一个测试类:

@SpringBootTest
class ConcurrentUpdateTest {
    @Autowired
    private UserService userService;

    @Test
    void testConcurrentUpdate() throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        CountDownLatch countDownLatch = new CountDownLatch(2);

        executorService.execute(() -> {
            try {
                userService.update();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            countDownLatch.countDown();
        });

        executorService.execute(() -> {
            try {
                userService.update();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            countDownLatch.countDown();
        });

        countDownLatch.await();
    }
}

在测试方法中,创建两个线程并发执行更新操作,通过CountDownLatch来保证两个线程都执行完毕后再结束测试

springboot + mybatis-plus 事务并发更新同一行数据导致更新丢失给出保证并发的前提下的解决方法不使用乐观锁 附上完整代码

原文地址: https://www.cveoy.top/t/topic/dbJo 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录