插入还是更新

如果有指定的记录就更新,否则插入

1. 传统方法

  1. if(select) {
  2. update
  3. } else {
  4. insert
  5. }

问题:

  1. if 读 then 写 必然存在并发问题,即使使用事务也无法解决(除非select使用锁定读)
  2. 至少两次查询,效率低

2. 删除再插入(replace into)

  1. replace into table(id,imei) values(x1,x2)

删除可能违反唯一约束的记录,然后再插入,相当于:

  1. //假设id、imei都有唯一约束
  2. delete from table where id = x1
  3. delete from table where imei = x2
  4. insert into table(id,imei) values(x1,x2)

问题:

  1. 使用自增主键的情况下,删插不能和改相提并论,会让与id有关联的其他表产生问题

    删+插 ≠ 改

  2. 几个唯一约束就有几条delete被执行,效率较差

3. on duplicate key

  1. insert into table(id,imei) values(x1,x2)
  2. on duplicate key
  3. update id = x1,imei = x2

我认为 它的执行逻辑应该是 try { insert… } catch(DuplicateKeyException e) { update… }

问题:

  1. update也会使主键增长,这是由于innodb对自增长主键的优化导致的(自增主键使用互斥量而非表锁)

    取消此优化可避免这个问题,但是插入会导致整体效率变差

  2. 如果id、imei都是唯一约束,id = x1和imei = x2是两条不同的记录时会如何?

数据库两条数据

id(自增主键) myid imei
1 1 456
2 2 234
  1. insert into table(myid,imei) values(1,234)
  2. on duplicate key
  3. update myid = 1,imei = 234

结果:

  1. INSERT INTO on_duplicate_key_test VALUES(1,234)
  2. on DUPLICATE KEY
  3. UPDATE myid = 1,imei = '234'
  4. > 1062 - Duplicate entry '234' for key 'imei_index'
  5. > 时间: 0.022s

看来on duplicate key只会处理第一个唯一约束的字段,即只是去更新 myid = 1 的记录,然后发现违反了imei的唯一约束,最后返回了失败(Mysql5.7.17)

另外 这种方法不会更改自增主键,除非在on duplicate key update 后指定修改主键