收藏夹吃灰系列:插入更新sql语句 ON DUPLICATE KEY UPDATE 使用详解 | 超级详细,建议收藏!

Posted bug菌√

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了收藏夹吃灰系列:插入更新sql语句 ON DUPLICATE KEY UPDATE 使用详解 | 超级详细,建议收藏!相关的知识,希望对你有一定的参考价值。

一:使用背景

        在项目中,你可能遇到这么一种场景,由于业务需求,需要先根据某一字段值查询数据库中是否有记录,有则更新,没有则插入。

        对于这种需求,我想先看看大家是怎么玩的,在想听到大家怎么实现该需求之前,我先给介绍一下,我前同事的实现逻辑,后续就是该代码被弃用,进而被优化。

        基本就是如下进行逻辑并合先进行查询再进行新增或更新操作。

if not exists (select task_name from task where task_name = target_name)
      insert into task(task_name ,point_ids,substation_id) values('target_name','point_ids','substation_id')
else
      update task set task_name = 'target_name',point_ids= 'point_ids',substation_id= 'substation_id' where task_name = target_name

虽然这样写在大多数情况下可以满足我们的需求,但是会有两个问题。

①性能带来开销,尤其是系统比较大的时候。

②在高并发的情况下会出现错误,可能需要利用事务保证安全。

... ...

那么是否有更优雅的玩法?

肯定是有的,今天bug菌就给大家介绍一种超牛的写法,。

ON DUPLICATE KEY UPDATE

没错,就是它啦。

肯定很多小伙伴都见过,那具体怎么玩呢,请听我一一道来。

 二、ON DUPLICATE KEY UPDATE 介绍

mysql数据库中,如果在insert语句后面带上ON DUPLICATE KEY UPDATE 子句,

而要插入的行与表中现有记录的惟一索引或主键中产生重复值,那么就会发生旧行的更新;

如果插入的行数据与现有表中记录的唯一索引或者主键不重复,则执行新纪录插入操作。

... ...

说通俗点就是数据库中存在某个记录时,执行这个语句会更新,而不存在这条记录时,就会插入。

三、ON DUPLICATE KEY UPDATE 用法

Insert into tablename(field1,field2,field3,......) values(value1,value2,value3,....) 
on duplicate key update field1=value1,field2=value2,field3=value3,......;

注意点:
因为这是个插入语句,所以不能加where条件。

四、实例演示

TaskMapper.java

void insertOrUpdate(@Param("tasks") List<Task> tasks, @Param("substationId") Integer substationId);

TaskMapper.xml

<insert id="insertOrUpdate">
    insert into task(task_name,point_ids,substation_id)VALUES
    <foreach item="item" collection="tasks" open="(" separator="," close=")">
        #{item.taskName}, #{item.pointIds},#{substationId}
    </foreach>
    ON DUPLICATE KEY UPDATE
    point_ids = VALUES(point_ids),substation_id = VALUES(substation_id);
</insert>

提问1:

平时执行单sql Affected rows 结果要么是1,要么是0,咋这条sql执行ssqlAffected rows是2呢?

 ... ...大大的疑惑,有木有

带大家看看官方文档的说明就明白了

原文:

With ON DUPLICATE KEY UPDATE, the affected-rows value per row is 1 if the row is inserted as a new row, 2 if an existing row is updated, and 0 if an existing row is set to its current values

翻译过来也就是说:

如果是插入操作,受到影响行的值为1;如果更新操作,受到影响行的值为2;如果更新的数据和已有的数据一样(就相当于没变,所有值保持不变),受到影响的行的值为0。

... ...

这下大家可明白了?

提问2:

        发现使用该子句自增id会跳长,本来自增id 到10,下一次自增id应该为11,但是下一次新增成功记录后,却发现自增id为12了?为啥呢,而且增长跨度和SQL的执行次数还成正比。

答:其实这很好理解,ON DUPLICATE KEY UPDATE 的一次执行,代表更新操作也会使自增ID加1的。

当然,自增ID在许多业务中只是作为一个记录唯一性标识而已,跳跃增长影响并不大。 

五、总结

1:ON DUPLICATE KEY UPDATE 需要有在INSERT语句中有存在主键或者唯一索引的列,并且对应的数据已经在表中才会执行更新操作。而且如果要更新的字段是主键或者唯一索引,不能和表中已有的数据重复,否则插入更新都失败。

2:不管是更新还是增加语句都不允许将主键或者唯一索引的对应字段的数据变成表中已经存在的数据。 


 往期热文推荐:


 OK,今天的文章先写到这。如果问题还请及时批评指正。

❤如果文章对您有所帮助,就请在文章末尾的左下角把大拇指点亮吧!(#^.^#);

❤如果喜欢bug菌分享的文章,就请给bug菌点个关注吧!(๑′ᴗ‵๑)づ╭❤~;

❤对文章有任何问题欢迎小伙伴们下方留言或者入群探讨【群号:708072830】;

❤鉴于个人经验有限,所有观点及技术研点,如有异议,请直接回复参与讨论(请勿发表攻击言论,谢谢);

❤版权声明:本文为博主原创文章,转载请附上原文出处链接和本文声明,版权所有,盗版必究!(*^▽^*).

以上是关于收藏夹吃灰系列:插入更新sql语句 ON DUPLICATE KEY UPDATE 使用详解 | 超级详细,建议收藏!的主要内容,如果未能解决你的问题,请参考以下文章

收藏夹吃灰系列:解决Win10插入U盘不显示磁盘可用容量且打不开卡死问题 | 超级详细,建议收藏

进收藏夹吃灰系列——Java基础快速扫盲

收藏夹吃灰系列:Springboot配置Thymeleaf实现静态页面访问 | 超级详细,建议收藏!

收藏夹吃灰系列:Springboot配置Thymeleaf实现静态页面访问 | 超级详细,建议收藏!

首次公开,整理12年积累的博客收藏夹,零距离展示《收藏夹吃灰》系列博客

收藏夹吃灰系列:谁说Spring提供的@Scheduled定时不好用?师妹看了直呼叫好!