进行商品表基础设计

create TABLE product(
    `id` BIGINT(10) UNSIGNED COMMENT 'id',
    `title` VARCHAR(20) COMMENT '商品名称',
    `quntity` BIGINT(10) COMMENT '商品数量' 
)

INSERT INTO product VALUES(1,'product_1',10);
INSERT INTO product VALUES(2,'product_1',10);
INSERT INTO product VALUES(3,'product_1',10);

#增加时间属性
ALTER TABLE product ADD COLUMN `created_at` Date COMMENT '创建时间';
#设置主键
ALTER TABLE product ADD  primary key(id);
ALTER TABLE product MODIFY COLUMN `id` AUTO_INCREMENT;
#修改字段名称
ALTER TABLE product RENAME COLUMN `quntity` TO `quantity`;

实现方式一(Mysql 乐观锁)、

Mybatis-plus中<span class="ne-text">@version</span>实现

@Version
private Integer version;

<span class="ne-text">@version</span>与Sql语句<span class="ne-text">update xxx set quantity=value,version = version + 1 where xx=xx and version = #{version}</span>同等意义。

具体代码实现如下

// 库存检查,订单创建。
        Product product = productMapper.selectOne(new QueryWrapper<Product>().lambda().eq(Product::getId, orderCreateRequest.getId()));
        if (product == null)
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "商品不存在");

        // 检查库存是否充足
        if (orderCreateRequest.getQuantity() > product.getQuantity()) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "库存不足");
        }

        if (product.getQuantity() <= 0) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "库存不足");
        }
        // 更新库存
        productMapper.update(product, new UpdateWrapper<Product>().lambda()
                .set(Product::getQuantity, (product.getQuantity() - orderCreateRequest.getQuantity()))
                .eq(Product::getId, product.getId()));

sql语句进行实现

通过version实现乐观锁。

public interface ProductMapper extends BaseMapper<Product> {
    @Update("update product set quantity = (quantity - ${orderCreateRequest.quantity}),version = version + 1 where id = #{orderCreateRequest.id} and version = version")
    int updateQuantity(@Param("orderCreateRequest") OrderCreateRequest orderCreateRequest,@Param("version") int version);
}

具体代码业务实现

@Transactional
public void createOrder(OrderCreateRequest orderCreateRequest) {
    // 库存检查,订单创建。
    Product product = productMapper.selectOne(new QueryWrapper<Product>().lambda().eq(Product::getId, orderCreateRequest.getId()));
    if (product == null)
        throw new BusinessException(ErrorCode.SYSTEM_ERROR, "商品不存在");

    // 检查库存是否充足
    if (orderCreateRequest.getQuantity() > product.getQuantity()) {
        throw new BusinessException(ErrorCode.SYSTEM_ERROR, "库存不足");
    }

    if (product.getQuantity() <= 0) {
        throw new BusinessException(ErrorCode.SYSTEM_ERROR, "库存不足");
    }
    // 更新库存
    productMapper.updateQuantity(orderCreateRequest,product.getVersion());
}

实现方式二(Redisson分布式锁)

获取分布式锁

String lockKey = "Product_" + product.getId();
RLock lock = redissonClient.getLock(lockKey);
try {
    if(lock.tryLock(0,-1, TimeUnit.MILLISECONDS)) {
        // 检查库存是否充足
        if (orderCreateRequest.getQuantity() > product.getQuantity()) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "库存不足");
        }
        if (product.getQuantity() <= 0) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "库存不足");
        }
        productMapper.update(product, new UpdateWrapper<Product>().lambda()
                .set(Product::getQuantity, (product.getQuantity() - orderCreateRequest.getQuantity()))
                .eq(Product::getId, product.getId()));
    }
} catch (InterruptedException e) {
    throw new BusinessException(ErrorCode.SYSTEM_ERROR,e.getMessage());
} finally {
    if(lock.isHeldByCurrentThread()){
        lock.unlock();
    }
}

思考

version字段到底做了什么样的操作实现了防止库存超出的问题。

最后修改:2024 年 04 月 26 日
如果觉得我的文章对你有用,请随意赞赏