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

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

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

1.添加唯一索引。

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

 

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 ,当然再后台代码中也要做是否存在记录检验,虽然不加锁不能完全避免重复,但也要尽量减少不是。(此条权当玩笑吧 ->_->)。

 

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

你可能感兴趣的:(数据库)