猿们好,我是honery,今天来给大家唠一唠如何避免数据库报唯一性约束的错误。
一、问题的引出
首先抛出一个问题,如何保证数据库表中的某列的值都不一样呢?相信大家很容易想到给该列加上唯一性约束
,这样就能保证业务逻辑的正确性了。实际的使用中,尤其高并发场景下,很容易出现插入同一条记录的情况,该情况下数据库会报违反唯一性约束的错误。总不能让数据库一直抛这个错误吧。于是我们想到可以在业务代码中加上该列值是否为空的判断,判断为空时再行插入,于是问题就解决了。
问题真的解决了吗?说是,你就too young too simple了。有没考虑过高并发场景
呢?如果多个线程同时在某次插入前去判空,显然判断的结果都是空,那么第一次插入成功后,后续的插入动作都会报违反数据库唯一性约束的错误。总不能让日志一直报错吧,该如何解决呢?
二、问题的解决方案
这个问题其实是个典型的问题,可以有很多种解决方案,小编这里就简单提供三种解决策略。方案很简单,猿们跟上思路~~
2.1 通过锁机制,将查询和插入原子化
相信很多小伙伴很容易就能想到这个方案,通过锁机制(如内置锁,synchronized
)将记录是否存在的查询动作和插入新记录的动作放在一个同步锁中,实现的关键代码如下:
@Transactional
public synchronized void insertWhenIdIsEmpty(Qingmj qingmj) {
log.info("进入时间:"+System.currentTimeMillis());
log.info(qingmj.toString());
Qingmj qingmj_old = qingmjMapper.getQingmjById(qingmj.getId());
try {
//等待10s,制造并发场景
Thread.sleep(15000);
} catch (InterruptedException e) {
log.warn("睡眠等待过程异常",e);
}