>  기사  >  Java  >  MyBatisPlus+SpringBoot를 사용하여 낙관적 잠금 기능을 구현하는 방법

MyBatisPlus+SpringBoot를 사용하여 낙관적 잠금 기능을 구현하는 방법

WBOY
WBOY앞으로
2023-05-11 20:46:11845검색

    1. 쇼핑몰 데이터가 일치하지 않는 시나리오

    쇼핑몰에 제품이 있는 경우 원가는 80위안, 판매가는 100위안입니다. 관리자는 먼저 Xiao Li에게 상품 가격을 50위안 인상해야 한다고 알렸습니다. Xiao Li는 게임을 하다가 한 시간 동안 지연되었습니다. 정확히 한 시간 후, 관리자는 제품 가격이 150위안으로 올랐는데, 이는 너무 높아 판매에 영향을 미칠 수 있다고 느꼈습니다. 또한 Xiao Wang에게 제품 가격을 30위안 인하하겠다고 알립니다.

    현재 Xiao Li와 Xiao Wang은 제품 백엔드 시스템을 동시에 운영하고 있습니다. Xiao Li가 작동할 때 시스템은 먼저 제품 가격 100위안을 인출하고 Xiao Wang도 작동하며 제품 가격도 100위안을 인출합니다. Xiao Li는 가격에 50위안을 추가하고 100+50=150위안을 데이터베이스에 저장했습니다. Xiao Wang은 제품을 30위안 줄이고 100-30=70위안을 데이터베이스에 저장했습니다. 예, 잠금 장치가 없으면 Xiao Li의 작업은 Xiao Wang의 작업에 완전히 포함됩니다.

    현재 제품 가격은 70위안으로 원가보다 10위안 저렴합니다. 몇 분 만에 이 제품의 1,000개 이상의 품목이 빠르게 판매되었고 사장은 10,000위안 이상의 손실을 입었습니다.

    두 번째, 이 프로세스를 보여줍니다

    1. 데이터베이스에 제품 테이블을 추가합니다

    CREATE TABLE product
    (
        id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
        name VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称',
        price INT(11) DEFAULT 0 COMMENT '价格',
        version INT(11) DEFAULT 0 COMMENT '乐观锁版本号',
        PRIMARY KEY (id)
    );
    
    INSERT INTO product (id, NAME, price) VALUES (1, '笔记本', 100);

    2. 엔터티 클래스를 생성합니다

    @Data
    public class Product {
        private Long id;
        private String name;
        private Integer price;
        private Integer version;
    }

    3. 테스트를 수행합니다

    public interface ProductMapper extends BaseMapper<Product> {
        
    }

    . 70위안, 관리자가 예상한 120위안이 달라 손실이 발생합니다. 이러한 이상 현상이 발생하지 않도록 하려면 어떻게 해야 할까요? 해결책은 낙관적 잠금을 사용하는 것입니다

    3. 낙관적 잠금 방식

    버전 필드를 데이터베이스에 추가하세요. : 레코드를 검색할 때 현재 버전을 가져옵니다

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class ProductVersionTest {
    	@Resource
    	private ProductMapper productMapper;
    	
    	@Test
    	public void testProductUpdate() {
    	
    	    //1、小李
    	    Product p1 = productMapper.selectById(1L);
    	
    	    //2、小王
    	    Product p2 = productMapper.selectById(1L);
    	
    	    //3、小李将价格加了50元,存入了数据库
    	    p1.setPrice(p1.getPrice() + 50);
    	    int result1 = productMapper.updateById(p1);
    	    System.out.println("小李修改结果:" + result1);
    	
    	    //4、小王将商品减了30元,存入了数据库
    	    p2.setPrice(p2.getPrice() - 30);
    	    int result2 = productMapper.updateById(p2);
    	    System.out.println("小王修改结果:" + result2);
    	
    	    //最后的结果
    	    Product p3 = productMapper.selectById(1L);
    	    System.out.println("最后的结果:" + p3.getPrice());
    	}
    }

    업데이트할 때 버전 + 1. where 문의 버전이 올바르지 않으면 업데이트가 실패합니다

    SELECT id,`name`,price,`version` FROM product WHERE id=1

    4. 낙관적 잠금 구현 프로세스

    1.

    @Version 주석 추가

    UPDATE product SET price=price+50, `version`=`version` + 1 WHERE id=1 AND `version`=1

    2. 낙관적 잠금 플러그인 추가

    @Version
    private Integer version;

    3. 프로세스 최적화

    (두 번째 데이터 업데이트가 성공했는지 확인하고, 그렇지 않은 경우 업데이트를 위해 데이터를 다시 가져옵니다.)

    @Configuration
    //@MapperScan("com.koo.modules.*.dao")
    public class MybatisPlusConfig {
    
        /**
         * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
         */
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
            //实现乐观锁,保证数据的准确性
            interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
            return interceptor;
        }
    
        @Bean
        public ConfigurationCustomizer configurationCustomizer() {
            return configuration -> configuration.setUseDeprecatedExecutor(false);
        }
    
    }

    출력 결과는 120이며, 데이터가 정확합니다

    위 내용은 MyBatisPlus+SpringBoot를 사용하여 낙관적 잠금 기능을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    성명:
    이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제