一、背景
统一关系数据库中,每张表必须包含的字段(称为系统字段),便于统一数据库开发规范,便于大数据抽取数据等;
二、系统字段定义
- 字段名标准
- 字段名统一采用英文
- 字段名要完整,准确,尽量避免简写(state/status、tid/cid/uid/aid...)
- 字段名不要含有无意义的前缀(p_uid/l_cid/a_order)
- 不同单词之间用‘_’字符分隔
- 必有字段
名称 | 类型 | 可空 | 默认值 | 说明 |
---|---|---|---|---|
id | bigint | 否 | 无符号,自增,主键;业务量小可选择 int 型 | |
sys_version | int | 否 | 第一次插入值为 0,之后乐观锁维护原则 | |
create_pin | varchar(50) | 否 | 只有第一次插入时维护为当前操作人 | |
create_time | datetime | 否 | now() | 只有第一次插入时维护 |
update_pin | varchar(50) | 是 | 每次更新都要记录当前操作人 | |
update_time | datetime | 否 | now() | 每次业务更新都取 DB 当前时间 now()即可 |
yn | tinyint | 否 | 0:有效,可维护,1:已逻辑删除,只能查询 | |
udt | timestamp | 否 | CURRENT_TIMESTAMP | DB 自动维护,用于大数据抽数,不维护 |
三、乐观锁维护原则
-
使用版本号的乐观锁 SQL 如下:
update tab_xxx
set column1=#{field1Value}, column2=#{field2Value},...
sys_version=sys_version+1, update_pin=#{updatePin}, update_time=now()
where
id=#{id} and sys_version=#{sysVersion} and yn=0
-
程序处理流程如下:
- 判断SQL更新影响行数。如果为 0,说明这条数据已经被其它线程更新,并发更新失败
- 反查数据。因为乐观锁导致,更新条数为0时(并发更新)要反查数据,如果已经改为目标结果,返回“已被他人执行成功”的结果,不能直接返回失败,也不能直接返回成功。
- 重试更新操作。具体重试采取系统再次取数据后更新的方式,还是提示给客户重新操作的方式,每个系统视具体场景而定。
-
常见问题:
- 有sysVersion却在update语句里没体现
- sql体现了sysVersion,在程序里没对更新结果条数做判断
- 对更新结果条数做了判断,但是只要条数为0就抛异常(实际可能已经被其它线程执行成功),没有就地反查比对结果
- 就地反查比对结果了,当前状态和预期状态一致就返回执行成功,没有告知是其它线程执行成功的,导致当前线程的调用方认为是自己执行成功的,进而执行后续逻辑(实际已经被其它相同逻辑的线程执行过)。
网友评论