mysql 存在则更新,不存在则插入的并发问题
比如有这样的场景:
- 操作一:检查表 table 中的 id=2 记录是否存在,存在,则更新这条记录,否则插入一条记录
- 操作二:检查表 table 中的 id=2 记录是否存在,存在,则更新这条记录,否则插入一条记录
有多中这样的操作,分别被封装进不同的服务里,请问有哪些方法可以防止同时插入两(多)条呢?
开发环境:Spring boot + mybatis
自己看了下,可以用@Transactional(isolation = Isolation.Serializable)
注解;或是将 id 设置为 unique;或是用复合 sql 语句(exist 之类的),请问哪种更好,或是有没有更好的方法。
各位大神,交流的时候突然又想起一个场景:
- 操作一:检查表 table 中的 id=2 记录是否存在,存在,则直接返回id,否则插入一条记录
- 操作二:检查表 table 中的 id=2 记录是否存在,存在,则直接返回id,否则插入一条记录
有多中这样的操作,分别被封装进不同的服务里,请问有哪些方法可以防止同时插入两(多)条呢?有查询到 insert ignore
但是这个方法,如果发现已有数据,会返回0,假如操作1和操作2同时查询id=2的记录发现不存在,然后操作1插入了一条记录,并返回自增id,操作2若用insert ignore
则返回0,感觉就不对了,会造成误解,请问有没有什么好的方法呢?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
隔离级别设置为可串行化很可能会影响数据库性能。
id
设为unique
。参考: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)
这个对于性能来说更好。
我是直接加了一个锁,但这样会影响性能。 若对性能要求不高可以用我这个方法。
https://kyle.net.cn/2017/11/0...
第二种场景是不是可以考虑设置 unique key,使用普通 insert,发生异常后延迟重试的机制。
这个就是很典型的并发问题啊,队列就解决了。
先把记录全部入队,然后统一出队。
可以尝试REDIS来进行缓存并去重操作 定时再将数据插入数据库