库存类表设计是电商、仓储类系统的核心环节,除了要能准确记录当前各商品的库存数量,还需要完整留存每一次库存变动的轨迹,方便后续进行库存对账、异常追溯、变动统计等操作。一套合理的库存表设计需要同时覆盖当前库存存储和变动历史记录两个核心部分。

基础库存表设计
基础库存表用于存储当前各商品、各仓库的实时库存数量,字段需要覆盖核心的库存标识、关联信息和状态字段,避免后续业务扩展时出现字段不足的问题。推荐的基础库存表结构如下:
-- 创建库存基础表 CREATE TABLE `inventory` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '库存记录ID', `product_id` bigint(20) NOT NULL COMMENT '商品ID', `warehouse_id` bigint(20) NOT NULL COMMENT '仓库ID', `current_quantity` int(11) NOT NULL DEFAULT 0 COMMENT '当前库存数量', `locked_quantity` int(11) NOT NULL DEFAULT 0 COMMENT '锁定库存数量', `version` int(11) NOT NULL DEFAULT 1 COMMENT '版本号,用于乐观锁控制并发', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_product_warehouse` (`product_id`,`warehouse_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品库存基础表';
表中product_id和warehouse_id组成唯一索引,确保同一个商品在同一个仓库下只有一条库存记录。locked_quantity字段用于存储已下单但未出库的商品数量,避免超卖。version字段用于乐观锁控制,当更新库存时校验版本号,防止并发更新导致的数据不一致。
数量变动历史表设计
数量变动历史表用于记录每一次库存变动的详细信息,包括变动类型、变动前后的数量、操作人、关联业务单号等,确保每一条库存变动都可追溯。推荐的数量变动历史表结构如下:
-- 创建库存变动历史表 CREATE TABLE `inventory_change_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '变动记录ID', `inventory_id` bigint(20) NOT NULL COMMENT '关联的库存基础表ID', `product_id` bigint(20) NOT NULL COMMENT '商品ID', `warehouse_id` bigint(20) NOT NULL COMMENT '仓库ID', `change_type` varchar(20) NOT NULL COMMENT '变动类型:入库、出库、锁定、解锁、盘点调整', `change_quantity` int(11) NOT NULL COMMENT '变动数量,正数表示增加,负数表示减少', `before_quantity` int(11) NOT NULL COMMENT '变动前库存数量', `after_quantity` int(11) NOT NULL COMMENT '变动后库存数量', `related_order_no` varchar(64) DEFAULT NULL COMMENT '关联业务单号,如采购单号、订单号', `operator_id` bigint(20) DEFAULT NULL COMMENT '操作人ID', `change_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '变动时间', `remark` varchar(255) DEFAULT NULL COMMENT '变动备注', PRIMARY KEY (`id`), KEY `idx_product_warehouse` (`product_id`,`warehouse_id`), KEY `idx_change_time` (`change_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='库存数量变动历史表';
表中inventory_id关联库存基础表的主键,方便快速关联查询当前库存信息。change_type字段明确变动的业务类型,后续可以根据类型统计不同业务的库存变动情况。before_quantity和after_quantity记录变动前后的库存值,即使基础库存表数据出现异常,也可以通过历史表还原变动轨迹。
常见库存变动操作示例
商品入库操作
商品入库时,需要先更新库存基础表的当前数量,再插入一条变动历史记录,两个操作需要在同一个事务中完成,保证数据一致性。
-- 商品入库事务操作示例
START TRANSACTION;
-- 1. 更新库存基础表,使用乐观锁防止并发冲突
UPDATE `inventory`
SET `current_quantity` = `current_quantity` + 100,
`version` = `version` + 1
WHERE `id` = 1
AND `version` = 1;
-- 校验更新是否成功,如果影响行数为0说明版本号不匹配,事务回滚
-- 2. 插入变动历史记录
INSERT INTO `inventory_change_log` (
`inventory_id`,
`product_id`,
`warehouse_id`,
`change_type`,
`change_quantity`,
`before_quantity`,
`after_quantity`,
`related_order_no`,
`operator_id`,
`remark`
) VALUES (
1,
1001,
10,
'入库',
100,
50,
150,
'CG20240501001',
10001,
'采购入库'
);
COMMIT;
订单锁定库存操作
用户下单时,需要锁定对应商品的库存,避免其他订单重复购买导致超卖,锁定操作只更新锁定库存字段,不改变当前库存数量。
-- 订单锁定库存事务操作示例
START TRANSACTION;
-- 1. 更新库存基础表,锁定对应数量的库存
UPDATE `inventory`
SET `locked_quantity` = `locked_quantity` + 2,
`version` = `version` + 1
WHERE `id` = 1
AND `current_quantity` - `locked_quantity` >= 2
AND `version` = 2;
-- 校验更新是否成功,影响行数为0说明库存不足,事务回滚
-- 2. 插入变动历史记录
INSERT INTO `inventory_change_log` (
`inventory_id`,
`product_id`,
`warehouse_id`,
`change_type`,
`change_quantity`,
`before_quantity`,
`after_quantity`,
`related_order_no`,
`operator_id`,
`remark`
) VALUES (
1,
1001,
10,
'锁定',
2,
150,
148,
'DD20240501001',
10002,
'用户下单锁定库存'
);
COMMIT;
设计注意事项
- 库存变动历史表的数据量会随时间快速增长,建议根据
change_time字段做分表处理,比如按季度或者按年分表,提升查询效率。 - 所有库存变动操作必须放在事务中执行,且优先更新库存基础表,再插入变动历史记录,避免历史记录插入成功但库存更新失败导致的数据不一致。
- 变动历史表的
change_type字段建议使用枚举值约束,避免插入无效的变动类型,保证数据规范性。 - 如果业务中存在多仓库调拨的场景,需要在变动类型中增加调拨出库和调拨入库类型,同时记录调拨的源仓库和目标仓库信息。
合理的库存表设计需要兼顾当前库存的准确性和变动历史的可追溯性,两个表通过关联字段形成完整的数据链路,才能满足业务长期发展的数据需求。