业务场景
有一个XX的Web系统里,要求用户列表里的用户是唯一的,具体是通过用户名称的字段(简单理解,)进行判定。在最早一版迭代里,为了简单,将用户名称设置为了唯一性索引
坑一:当索引字段取值为null时数据唯一效果失效
唯一性索引的第一个坑,是被索引的字段是可以为null的。在Mysql innodb引擎中,允许在唯一索引的字段中出现多个null值。两个null是不会被判定为相等的值
ALTER TABLE t
ADD UNIQUE(n1,n2)
n1 | n2 |
---|---|
1 | null |
1 | null |
像这个例子,是可以成功创建到带有唯一索引的表中,却不符合实际用户的感知的
在业务场景中,通过限制了被归纳到唯一性索引中的所有字段,都不允许为null来规避了这个事情,接着又迎来了第二个坑
坑二:删除场景从逻辑删除变为物理删除时,无法添加新数据
随着业务规模的扩大和真实用户需求的涌入,为了提高数据安全和容灾能力,需要将删除用户的操作从物理删除修改为逻辑删除。通用做法就是增加状态字段status,例如0标识数据有效,当执行删除操作时,将status修改为1
问题在于,将某一用户删除后,系统中再次添加用户,填写了和被删除用户一样的信息,由于有唯一性索引的存在,导致这两条数据不满足约束,从而添加失败。又一次产生了不符合实际用户需求的问题
方案一
status字段的值,随着删除操作依次递增。例
- 初始值是0,(n1,n2,status=0)
- 当第一次删除时,该数据的status设置为1。(n1,n2,status=1)
- 写入新数据,status=0。(n1,n2,status=0)(n1,n2,status=1)
- 删除新数据,status设置为当前系统中最大值+1(1+1)为2。 (n1,n2,status=1)(n1,n2,status=2)
- 写入新数据,(n1,n2,status=0)(n1,n2,status=1)(n1,n2,status=2)
- 再次删除时,status设置为当前系统中最大值+1(2+1)为3。(n1,n2,status=1)(n1,n2,status=2)(n1,n2,status=3)
方案二
类似,也是向唯一性约束靠拢,将标识状态的status字段取值唯一,删除时将其设置为当前时间戳或者设置为primary key的值。
关于设置为时间戳,高并发时是否会导致系统出问题?可以讨论一下,目前看不会。插入或者编辑操作时,数据库保证只写入成功一次,其余会失败;删除操作时,由于操作的数据在前置条件中是保证了唯一,也不会出现问题
方案n
整体去掉数据库层的唯一约束,通过应用层的代码来判断,是否存在重复数据,即应用层在进行insert和update操作前,增加一次查询数据库的操作
结语
良好的编程习惯,从小事做起,从一开始做起
网友评论