SpringBoot整合MybatisPlus3.X之樂觀鎖(十三)


主要適用場景

意圖:

當要更新一條記錄的時候,希望這條記錄沒有被別人更新

樂觀鎖實現方式:

  • 取出記錄時,獲取當前version

  • 更新時,帶上這個version

  • 執行更新時, set version = newVersion where version = oldVersion

  • 如果version不對,就更新失敗

樂觀鎖配置需要2步 記得兩步

1.插件配置

spring xml:

<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>
spring boot:

@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    return new OptimisticLockerInterceptor();
}

 

2.注解實體字段 @Version 必須要!

@Version
private Integer version;

特別說明:

  • 支持的數據類型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime

  • 整數類型下 newVersion = oldVersion + 1

  • newVersion 會回寫到 entity

  • 僅支持 updateById(id)update(entity, wrapper) 方法

  • update(entity, wrapper) 方法下, wrapper 不能復用!!!

示例

示例Java代碼(參考代碼)

int id = 100;
int version = 2;
​
User u = new User();
u.setId(id);
u.setVersion(version);
u.setXXX(xxx);
​
if(userService.updateById(u)){
    System.out.println("Update successfully");
}else{
    System.out.println("Update failed due to modified by others");
}

示例SQL原理

update tbl_user set name = 'update',version = 3 where id = 100 and version = 2
  • pom.xml

    <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.2.0</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
            <!-- https://mvnrepository.com/artifact/p6spy/p6spy -->
            <dependency>
                <groupId>p6spy</groupId>
                <artifactId>p6spy</artifactId>
                <version>3.8.0</version>
            </dependency>
            <dependency>
                <groupId>com.h2database</groupId>
                <artifactId>h2</artifactId>
                <scope>runtime</scope>
            </dependency><dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.49</version>
                <scope>test</scope>
            </dependency>
            <!-- for testing -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>

     

  • 配置類

    @Configuration
    public class MybatisPlusOptLockerConfig {
    ​
        @Bean
        public OptimisticLockerInterceptor optimisticLockerInterceptor() {
            return new OptimisticLockerInterceptor();
        }
    }
  • 實體類

    @Data
    public class User {
    ​
        @TableId(value = "id", type = IdType.AUTO)
        private Long id;
        private String name;
        private Integer age;
        private String email;
        @Version
        private Integer version;
    }
  • Mapper

    public interface UserMapper extends BaseMapper<User> {
    ​
    }
  • 啟動類

    @SpringBootApplication
    @MapperScan("com.mp.locker.mapper")  //不加在容器里面獲取不了
    public class LockerApplication {
    ​
        public static void main(String[] args) {
            SpringApplication.run(LockerApplication.class, args);
        }
    ​
    }
  • application.yml

    spring:
      datasource:
        driver-class-name: com.p6spy.engine.spy.P6SpyDriver
        url: jdbc:p6spy:h2:tcp://192.168.180.115:19200/~/mem/test
        username: root
        password: test
  • 測試類

    @SpringBootTest
    class LockerApplicationTests {
    ​
        @Autowired(required = false)
        UserMapper userMapper;
    ​
        @Test
        public void testUpdateByIdSucc() {
            User user = new User();
            user.setAge(18);
            user.setEmail("test@baomidou.com");
            user.setName("optlocker");
            user.setVersion(1);
            userMapper.insert(user);
            Long id = user.getId();
            //INSERT INTO user ( name, version, email, age ) VALUES ( 'optlocker', 1, 'test@baomidou.com', 18 )
            User userUpdate = new User();
            userUpdate.setId(id);
            userUpdate.setAge(19);
            userUpdate.setVersion(1);
            //UPDATE user SET version=2, age=19 WHERE id=6 AND version=1
            Assert.assertEquals("Should update success", 1, userMapper.updateById(userUpdate));
            //6 optlocker   19  test@baomidou.com   2  值變成2
            Assert.assertEquals("Should version = version+1", 2, userUpdate.getVersion().intValue());
        }
    ​
        @Test
        public void testUpdateByIdFail() {
            User user = new User();
            user.setAge(18);
            user.setEmail("test@baomidou.com");
            user.setName("optlocker");
            user.setVersion(1);
            //INSERT INTO user ( name, version, email, age ) VALUES ( 'optlocker', 1, 'test@baomidou.com', 18 )
            userMapper.insert(user);
            Long id = user.getId();
    ​
            User userUpdate = new User();
            userUpdate.setId(id);
            userUpdate.setAge(19);
            userUpdate.setVersion(0);
            //UPDATE user SET version=1, age=19 WHERE id=7 AND version=0
            userMapper.updateById(userUpdate);
        }
    ​
        @Test
        public void testUpdateByIdSuccWithNoVersion() {
            User user = new User();
            user.setAge(18);
            user.setEmail("test@baomidou.com");
            user.setName("optlocker");
            user.setVersion(1);
            userMapper.insert(user);
            Long id = user.getId();
    ​
            User userUpdate = new User();
            userUpdate.setId(id);
            userUpdate.setAge(19);
            userUpdate.setVersion(null);
            Assert.assertEquals("Should update success as no version passed in", 1, userMapper.updateById(userUpdate));
            User updated = userMapper.selectById(id);
            Assert.assertEquals("Version not changed", 1, updated.getVersion().intValue());
            Assert.assertEquals("Age updated", 19, updated.getAge().intValue());
        }
    ​
        /**
         * 批量更新帶樂觀鎖
         * <p>
         * update(et,ew) et:必須帶上version的值才會觸發樂觀鎖
         */
        @Test
        public void testUpdateByEntitySucc() {
            QueryWrapper<User> ew = new QueryWrapper<>();
            ew.eq("version", 1);
            int count = userMapper.selectCount(ew);
    ​
            User entity = new User();
            entity.setAge(28);
            entity.setVersion(1);
    ​
            Assert.assertEquals("updated records should be same", count, userMapper.update(entity, null));
            ew = new QueryWrapper<>();
            ew.eq("version", 1);
            Assert.assertEquals("No records found with version=1", 0, userMapper.selectCount(ew).intValue());
            ew = new QueryWrapper<>();
            ew.eq("version", 2);
            Assert.assertEquals("All records with version=1 should be updated to version=2", count, userMapper.selectCount(ew).intValue());
        }
    ​
    }

     


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM