mysql 存在则更新,不存在则插入的并发问题

Neil
  • 99

比如有这样的场景:

  1. 操作一:检查表 table 中的 id=2 记录是否存在,存在,则更新这条记录,否则插入一条记录
  2. 操作二:检查表 table 中的 id=2 记录是否存在,存在,则更新这条记录,否则插入一条记录

有多中这样的操作,分别被封装进不同的服务里,请问有哪些方法可以防止同时插入两(多)条呢?
开发环境:Spring boot + mybatis
自己看了下,可以用
@Transactional(isolation = Isolation.Serializable) 注解;或是将 id 设置为 unique;或是用复合 sql 语句(exist 之类的),请问哪种更好,或是有没有更好的方法。

各位大神,交流的时候突然又想起一个场景:

  1. 操作一:检查表 table 中的 id=2 记录是否存在,存在,则直接返回id,否则插入一条记录
  2. 操作二:检查表 table 中的 id=2 记录是否存在,存在,则直接返回id,否则插入一条记录

有多中这样的操作,分别被封装进不同的服务里,请问有哪些方法可以防止同时插入两(多)条呢?有查询到 insert ignore 但是这个方法,如果发现已有数据,会返回0,假如操作1和操作2同时查询id=2的记录发现不存在,然后操作1插入了一条记录,并返回自增id,操作2若用insert ignore则返回0,感觉就不对了,会造成误解,请问有没有什么好的方法呢?

回复
阅读 9.9k
8 个回答

隔离级别设置为可串行化很可能会影响数据库性能。
id设为unique

INSERT INTO t1 (a, b, c) VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE a=1, b=2, c=3;

参考:insert on duplicate

我的做法,可不使用@Transactional注解:

INSERT INTO t1 (a, b, c) VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE id=last_insert_id(id), a=1, b=2, c=3;

这样执行完查询后可以直接使用Statement.getGeneratedKeys获取到插入的自增ID或更新的记录ID

如果你的使用场景是高并发的话,单纯的读库是会有性能问题的,因为可能牵涉到mysql锁的使用,个人建议配合redis集合使用,通过集合的唯一性来解决这个问题。
在执行操作的时候先尝试向集合中添加元素,添加成功则说明不存在,添加失败则说明已存在。希望对你有帮助

replace into t1(id, column) values(2, column)
这个对于性能来说更好。

第二种场景是不是可以考虑设置 unique key,使用普通 insert,发生异常后延迟重试的机制。

这个就是很典型的并发问题啊,队列就解决了。

先把记录全部入队,然后统一出队。

可以尝试REDIS来进行缓存并去重操作 定时再将数据插入数据库

宣传栏