mybatis-plus乐观锁

mybatis-plus乐观锁

乐观锁vs悲观锁

悲观锁

假设:数据冲突是常态

策略:先锁定,再操作

心态:防御性编程

成本:前期投入大(锁的开销)

场景:写多读少

sql 复制代码
-- 悲观锁的思维方式
BEGIN TRANSACTION;
-- "我不相信别人,先锁住再说"
SELECT * FROM account WHERE id = 1 FOR UPDATE; -- 立即加锁

-- 只有我能操作
UPDATE account SET balance = balance - 100 WHERE id = 1;

COMMIT; -- 最后才释放锁

乐观锁

假设:数据冲突是例外

策略:通过版本号/时间戳检测数据变化,读取时不加锁,更新时检查

心态:乐观协作

成本:失败时重试成本

场景:读多写少

sql 复制代码
UPDATE product 
SET stock = 90, version = version + 1 
WHERE id = 1 AND version = 5
-- 如果version=5的记录存在,更新并返回1
-- 如果version已变(别人改了),更新0行

mybatis-plus乐观锁

添加版本字段

java 复制代码
@Data
@TableName("product")
public class Product {
    @TableId(type = IdType.AUTO)
    private Long id;
    
    private String name;
    private Integer stock;
    private BigDecimal price;
    
    @Version  // 核心注解!
    private Integer version;
}

配置乐观锁插件

java 复制代码
@Configuration
public class MybatisPlusConfig {
    
    /**
     * 乐观锁插件配置
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        
        // 乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        
        // 分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        
        return interceptor;
    }
}

使用乐观锁更新

java 复制代码
@Service
@Slf4j
public class ProductServiceV2 {
    
    private static final int MAX_RETRY = 3;
    
  
    @Transactional(rollbackFor = Exception.class)
    public boolean deductStockWithRetry(Long productId, Integer quantity) {
        int retryCount = 0;
        
        while (retryCount < MAX_RETRY) {
            try {
                // 每次重试都需要重新查询最新数据
                Product product = productMapper.selectById(productId);
                
                if (product.getStock() < quantity) {
                    log.warn("库存不足,productId: {}, stock: {}", 
                            productId, product.getStock());
                    return false;
                }
                
                product.setStock(product.getStock() - quantity);
                int rows = productMapper.updateById(product);
                
                if (rows > 0) {
                    log.info("扣减成功,productId: {}, 剩余库存: {}", 
                            productId, product.getStock());
                    return true;
                }
                
                // 更新失败,版本冲突,重试
                retryCount++;
                log.info("版本冲突,第{}次重试,productId: {}", 
                        retryCount, productId);
                
                // 指数退避:减少竞争
                Thread.sleep(50 * retryCount);
                
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new BusinessException("操作被中断");
            }
        }
        
        log.error("扣减失败,达到最大重试次数,productId: {}", productId);
        throw new BusinessException("系统繁忙,请稍后重试");
    }
}

秒杀系统

一般采用 乐观锁 + 分布式锁、

分布式锁控制流量

乐观锁控制数据的一致性

java 复制代码
@Slf4j
@Service
public class SeckillService {
    
    @Autowired
    private RedissonClient redissonClient;
    
    @Autowired
    private ProductMapper productMapper;
    
    public boolean seckillProduct(Long productId, Long userId) {
        String lockKey = "seckill:lock:" + productId;
        RLock lock = redissonClient.getLock(lockKey);
        
        try {
            // 分布式锁:控制并发入口
            if (!lock.tryLock(3, 10, TimeUnit.SECONDS)) {
                throw new BusinessException("排队人数过多,请稍后");
            }
            
            // 乐观锁:保证数据一致性
            return deductStockWithRetry(productId, 1);
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new BusinessException("系统繁忙");
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
相关推荐
2301_81123298几秒前
C++中的契约编程
开发语言·c++·算法
2401_829004021 分钟前
C++中的访问者模式
开发语言·c++·算法
黎雁·泠崖3 分钟前
Java内部类与匿名内部类:定义+类型+实战应用
java·开发语言
青槿吖9 分钟前
第二篇:JDBC进阶骚操作:防注入、事务回滚、连接池优化,一篇封神
java·开发语言·jvm·算法·自动化
赵萱婷9 分钟前
C++17 nodiscard属性深度解析
开发语言·c++·经验分享
kklovecode10 分钟前
C++对C语言的增强
c语言·开发语言·c++
hnxaoli18 分钟前
统信小程序(八)归档目录自动调整
linux·python
Tiger Z18 分钟前
《R for Data Science (2e)》免费中文翻译 (第18章) --- Missing values
开发语言·r语言
csbysj202022 分钟前
Python 列表(List)
开发语言