数据绑定的优点_你知道嘛?防止业务数据重复插入的另一种思路

d9b90179c86cf784d020fb18f9105020.png

引言

开门见山

近日降雨颇多,偶然迸发灵感,对于防止重复插入这个问题想到了另一种解决方案(方案三)。

一个场景

电商项目中,一个商品可以绑定多个标签,一个标签可以绑定多个商品,所以肯定会存在一个中间表对商品和标签的关联,假设关联表goods_label结构如下:

字段 类型 注释 id bigint 主键 goods_id bigint 商品id label_id bigint 标签id is_delete tinyint 逻辑删除标识,1为已删除,2为未删除 A和B同时对商品做标签绑定的操作:

A -> 绑定商品1和标签1B -> 绑定商品1和标签1复制代码

那么我们的期望是A和B的操作只会成功其一,另一个提醒他操作失败。

接下来将会有几种方案来达到我们想要的预期~

方案一:分布式锁

伪代码:

var goods_id = 1var label_id = 1var id = getId()var count = select count(0) from goods_label where goods_id = $goods_id and label_id = $label_id and is_delete = 2if count > 0{ return "已存在关联"}var l = lock.try(GOODS_LABEL_LOCK_KEY + goods_id)if l != nil{ try{ var row = insert into goods_label(id, goods_id, label_id, is_delete) values ($id, $goods_id, $label_id, 2) if row > 0{ return "成功" } return "失败" } finally{ l.release() }}else{ return "操作超时"}复制代码

这种很常用,也很普通...没有一丝灵魂

方案二:联合唯一索引

将goods_id和label_id以及is_delete设为联合唯一索引,那么伪代码可以这样写:

var goods_id = 1var label_id = 1var id = getId()var count = select count(0) from goods_label where goods_id = $goods_id and label_id = $label_id and is_delete = 2if count > 0{ return "已存在关联"}var row = insert into goods_label(id, goods_id, label_id, is_delete) values ($id, $goods_id, $label_id, 2)if row > 0{ return "成功"}return "失败"复制代码

代码简洁了不少,但是表的索引结构会复杂导致tps下降,is_delete字段也被限制了同一条记录只会存在1和2两个结果。

方案三:预删除(自命名)

var goods_id = 1var label_id = 1var id = getId()var count = select count(0) from goods_label where goods_id = $goods_id and label_id = $label_id and is_delete = 2if count > 0{ return "已存在关联"}var trans = beginTrans()// 1var row = insert into goods_label(id, goods_id, label_id, is_delete) values ($id, $goods_id, $label_id, 1)if row > 0{ // 2 row = update goods_label set is_delete = 2 where id = $id and (select t.count from (select count(0) as count from goods_label where goods_id = $goods_id and label_id = $label_id and is_delete = 2) t) = 0  if row > 0{ trans.commit() return "成功" } trans.rollback() return "失败"}return "失败"复制代码

这种方案会执行两条操作事务sql:

  • tag 1: 先插入数据,先将状态置为已删除。
  • tag 2: 再将之前插入的数据状态更新为未删除,但是前提是当前关联不存在

可以发现,如果tag 2执行失败,整个事务会回滚掉,那么tag 1的操作也会撤销,所以也不会产生脏数据。

方案对比

  • 方案一: 传统,但很实用,没有灵魂。
  • 方案二: 局限性太大,如果唯一的条件太多会导致索引更加复杂,另外is_delete有些场景也可能允许同类资源删除多次,这样的话无法达到唯一索引的效果。优点是业务代码很简洁!
  • 方案三: 本人偶尔突发奇想,不知道好坏,但是能达到目的 xD

小结

欢迎关注头条号:JAVA大飞哥

点击关注评论转发一波:私信小编发送“架构”(免费获取)

获取微服务、分布式、高并发、高可用,性能优化丶Mysql源码分析等等一些技术资料

最后,每一位读到这里的Java程序猿朋友们,感谢你们能耐心地看完。希望在成为一名更优秀的Java程序猿的道路上,我们可以一起学习、一起进步!都能赢取白富美,走向架构师的人生巅峰!

7bc962b9444ba3dfe94404c6b41f4975.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值