问:现在我的业务中有这样的需求:如果目标记录存在的话我就更新它,如果记录不存在的话我就插入。说说看你知道哪些实现方式吧!

答:

1. 判断逻辑:先查询,再更新/插入,会和Mysql发生2次网络交互。

  1. // 伪代码
  2. user=User.FindById(1)
  3. if user == null{
  4. user.Insert()
  5. }else{
  6. user.Update()
  7. }

缺点:

  • 会和Mysql发生2次网络交互;
  • 并发访问场景下,会有并发修改异常。

2.影响行数:先尝试更新,没有记录则影响行数为0,再插入,和Mysql的网络交互可能降低成1。

// 伪代码
effectRows=User.UpdateById(1)
if effectRows >0 {  
    user.Insert()
}

缺点:

  • update实例的信息与数据库中记录完全一致,update影响的行数为0,则执行insert语句,会报错主键冲突。

3.insert ignore into:如果记录存在了就ignore本次插入,如果记录不存在就写入。判断是否可以写入的标准是:唯一键不能重复。

insert ignore into table_name(id, name) values(1, 'jerry');

缺点:

  • insert ignore into 并不能满足我们的业务需求。只要你想写入的数据和现有的唯一键冲突了,最终就不会将你的数据落库。


4.replace into:如果记录存在了就更新,如果记录不存在就写入。

判断数据是否已经存在的标准依然是:唯一键是否重复。
而且这个替换还是全量替换:

replace into table_name(id, name) values(1, 'jerry');

5.on duplicate key update:如果记录存在(判断标准是主键)了就更新,如果记录不存在就写入。

insert into table_name(id, name) values(1, 'jerry') on duplicate key update name = 'tom';

缺点:

  • 多个唯一主键的时候,要避免使用;
  • 使用on duplicate key update即使实际执行的是update,也会调用LAST_INSERT_ID()函数,导致自增的主键id出现不再是递增的幻觉,而是跳着增长的。

image.png

问:先判断是否存在,再插入/插入,会有诸多并发修改异常,举个例子,并思考怎么避免?

1. 并发异常