一条SQL如何实现insertOrUpdate
题目
一条sql如何实现插入或更新
具体描述:有一张表,表中有两个字段id和name,现在往数据库中要插入一条数据,这条数据如果id不存在则插入,如果id存在则更新
分析
日常开发中,都是通过ORM框架实现,比如MybatisPlus提供的saveOrUpdate,或者使用Mybatis先查询判断id是否存在,然后分别执行insert或update。
MybatisPlus的saveOrUpdate存在问题
MybatisPlus的saveOrUpdate是一个非原子性操作,saveOrUpdate()内部先进行查询,再进行插入/更新,这两个操作都不是原子操作,在高并发场景下,无法保证操作的原子性。
如何解决
- 使用乐观锁
 在数据库表中添加版本号字段(如version),通过@Version注解实现乐观锁。更新时自动校验版本号,避免并发覆盖。@Version private Integer version;
- 加分布式锁
 在分布式系统中,可以对关键操作加上分布式锁(如Redission锁),确保在同一时间内只有一个节点能够执行saveOrUpdate()操作。
- 基于数据库层面实现
 也就说今天要说的一条sql实现插入或更新
方法
不同数据库的实现方法存在差别,这里只写三个库为例
Mysql
INSERT INTO  test(id, name) VALUES (1, 'zhangsan') ON DUPLICATE KEY UPDATE name='zhangsan';
# 或
REPLACE INTO test(id, name) value (1, 'zhangsan');
推荐 ON DUPLICATE KEY UPDATE实现
原因
- replace into:id存在会删除原记录,然后新增一条记录,如果主键id是自增会导致主键改变
- on duplicate key update:id存在会更新原记录,主键不变
Postgresql
INSERT INTO test(id, name) VALUES (1, 'zhangsan') ON CONFLICT (id) DO UPDATE SET name = 'zhangsan';
Sqlite
INSERT OR REPLACE INTO test(id, name) VALUES (1, 'zhangsan');
