数据库并发插入避免重复数据的问题

今天稍微研究了下这个问题从网上整理资料大致得到了如下方案,先粗略记录下,下班回去再更详细记录下。

所有的方法都先不考虑性能问题,也不考虑业务,只看逻辑上能否达到去重,因为第一,如果唯一性是必须要保证的,那么只能先实现了唯一,再去考虑优化;第二,如果能通过调整业务来规避,那我后面说的都是废话了还有什么看头。

1.添加唯一索引。

  但这种方法在表中有逻辑删除时会有问题。   

  后记:逻辑删除如果用ID来做删除标识,应该也行。设删除标识DEL_FLG,未删除的用0做标记,删除的用ID做标记。设需要去重的字段为FIELD_1,那么用FIELD_1和DEL_FLG组成联合索引。逻辑删除时将DEL_FLG设为与ID相同,未删除的DEL_FLG为0,

 这样联合索引不会影响已删除的,只会防止未删除数据的重复。

2.加锁。但是据查oracle中行锁只能是写时阻塞,且必须要该行数据存在,所以要确保你用来加锁的字段在某个表已经存在(不存在的话也锁不住),比如:如果你要在user_permission表中存储user和permission的关系且user-permission的组合只能存在一条记录。那么此时如果两个A,B进程同时都插入(user1,permission1)就会在表中产生重复数据。因为可以确定user1肯定已经在user表中存在,permission1肯定已经在permission表中存在,所以你可以考虑用这两个表中的一个来加锁,具体插入步骤如下:

a、select * from user u where u.user = user1 for update

b、select count(*) from user_permission up where up.user = user1 and up.permission = permission1 然后判断结果是否大于0

c、如果步骤b中结果等于0 则insert into from user_permission

按照以上的步骤,如果A进程先执行a步骤,则B进程会在a步骤阻塞,等A进程执行完后面两步以后,B进程才会继续执行b步骤,但此时A进程已经插入数据了,B进程查询count等于1就不再插入。

但这种方法也有问题:假如此时正巧有人需要在user表中修改user1的基础数据,就会被阻塞,等到别人执行完了才能执行;或者此时有个进程C想插入(user1,permisson2),虽然这条数据并没有与A,B冲突,但是因为进程C在a步骤也发现user1加锁了,所以也会阻塞,直到其他进程释放。

3.多个连接需要插入的数据全插入后台的buff里,然后在后台用一个线程专门处理和数据库的交互,从buff逐条读取,再往数据库插。因为最终插入数据库只有一个线程,所以只要在插入前检测一下表中是否存在就可以了。

但是这种在分布式系统中这种方法肯定就跪了。

4.并发的数据都插入数据库的中间表,然后做个后台存储过程将中间表的数据往业务表插,这个过程中就可以保证相同数据只插入一条。

5.先插入重复数据,再用后台存储过程删除多余的。

3,5 思想其实一样,不过一个是交给后台处理,一个是交给数据库处理。

 

其实还有一种方法,重复插入就重复插入呗。改,查的时候按最早插入时间来取第一条,删除的时候全删,统计的时候distinct ,当然在后台代码中也要做是否有已存在记录的检验,虽然不加锁不能完全避免重复,但也要尽量减少不是。(此条权当玩笑吧 ->_->)。

 

大家都懂的,菜鸟写博客多多少少都会有问题,希望大家指正。只知道冷嘲热讽的就不用来了,当然,讽完还能提建设性意见的我也可以接受 ->_->

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值