更新多条数据,每条数据都不一样

背景描述:通常如果需要一次更新多条数据有两个方式,(1)在业务代码中循环遍历逐条更新。(2)一次性更新所有数据(更准确的说是一条sql语句来更新所有数据,逐条更新的操作放到数据库端,在业务代码端展现的就是一次性更新所有数据)。两种方式各有利弊,下面将会对两种方式的利弊做简要分析,主要介绍第二种方式在mybatis中的实现。

逐条更新(效率低)(方法一)

这种方式显然是最简单,也最不容易出错的,即便出错也只是影响到当条出错的数据,而且可以对每条数据都比较可控,更新失败或成功,从什么内容更新到什么内容,都可以在逻辑代码中获取。代码可能像下面这个样子:

updateBatch(List<MyData> datas){
for(MyData data : datas){
try{
myDataDao.update(data);//更新一条数据,mybatis中如下面的xml文件的update
}
catch(Exception e){
...//如果更新失败可以做一些其他的操作,比如说打印出错日志等
}
}
} //mybatis中update操作的实现
<update>
update mydata
set ...
where ...
</update>

这种方式最大的问题就是效率问题,逐条更新,每次都会连接数据库,然后更新,再释放连接资源(虽然通过连接池可以将频繁连接数据的效率大大提高,抗不住数据量大),这中损耗在数据量较大的时候便会体现出效率问题。这也是在满足业务需求的时候,通常会使用上述提到的第二种批量更新的实现(当然这种方式也有数据规模的限制,后面会提到)。

逐条更新(方法二)

通过循环,依次执行多条update的sql

前提条件:

要实现批量更新,首先得设置mysql支持批量操作,在jdbc链接中需要附加&allowMultiQueries=true属性才行
例如:
jdbc:mysql://localhost:3306/dbname?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
<update id="updateBatch"  parameterType="java.util.List">
<foreach collection="list" item="item" index="index" open="" close="" separator=";">
update course
<set>
name=${item.name}
</set>
where id = ${item.id}
</foreach>
</update>

一条记录update一次,性能比较差,容易造成阻塞。

sql批量更新(一)(主力)

(可行)实际实践(传入的是List<Map<String, Object>>)

++务必注意:一定要加where条件,里面的id为需要更新的数据的id;如果不加where条件,则会全部更新,但是需要更新且有数据的更新为传递的数据,没有数据的则更新为null,此时更新出错++

<update id="updateChartParamByAccountAndChartid" parameterType="list">
update followme_parameters
<trim prefix="set" suffixOverrides=",">
<trim prefix="signal_source =case" suffix="end,">
<foreach collection="list" item="item" index="index">
<if test="item.signalSource!=null">
when account=#{item.account} and chart_id=#{item.chartId}
then #{item.signalSource}
</if>
</foreach>
</trim>
<trim prefix="rate =case" suffix="end,">
<foreach collection="list" item="item" index="index">
<if test="item.rate!=null">
when account=#{item.account} and chart_id=#{item.chartId}
then #{item.rate}
</if>
</foreach>
</trim>
</trim>
where id in
<foreach collection="list" item="item" index="index" separator="," open="(" close=")">
#{item.id}
</foreach>
</update>

下面逐步讲解

一条sql语句来批量更新所有数据,下面直接看一下在mybatis中通常是怎么写的(去掉mybatis语法就是原生的sql语句了,所有就没单独说sql是怎么写的)。

<update id="updateBatch" parameterType="java.util.List">
update mydata_table
set status=
<foreach collection="list" item="item" index="index"
separator=" " open="case ID" close="end">
when #{item.id} then #{item.status}
</foreach>
where id in
<foreach collection="list" index="index" item="item"
separator="," open="(" close=")">
#{item.id,jdbcType=BIGINT}
</foreach>
</update>

其中when...then...是sql中的"switch" 语法。这里借助mybatis的语法来拼凑成了批量更新的sql,上面的意思就是批量更新id在updateBatch参数所传递List中的数据的status字段。还可以使用实现同样的功能,代码如下:

<update id="updateBatch" parameterType="java.util.List">
update mydata_table
<trim prefix="set" suffixOverrides=",">
<trim prefix="status =case" suffix="end,">
<foreach collection="list" item="item" index="index">
when id=#{item.id} then #{item.status}
</foreach>
</trim>
</trim>
where id in
<foreach collection="list" index="index" item="item" separator="," open="(" close=")">
#{item.id,jdbcType=BIGINT}
</foreach>
</update> <trim>

属性说明

1.prefix,suffix 表示在trim标签包裹的部分的前面或者后面添加内容
2.如果同时有prefixOverrides,suffixOverrides 表示会用prefix,suffix覆盖Overrides中的内容。
3.如果只有prefixOverrides,suffixOverrides 表示删除开头的或结尾的xxxOverides指定的内容。

上述代码转化成sql如下:

update mydata_table
set status =
case
when id = #{item.id} then #{item.status}//此处应该是<foreach>展开值
...
end
where id in (...);

当然这是最简单的批量更新实现,有时候可能需要更新多个字段,那就需要将

<trim prefix="status =case" suffix="end,">
<foreach collection="list" item="item" index="index">
when id=#{item.id} then #{item.status}
</foreach>
</trim>

复制拷贝多次,更改prefix和when...then...的内容即可.而如果当需要为某个字段设置默认值的时候可以使用else

<trim prefix="status =case" suffix="end,">
<foreach collection="list" item="item" index="index">
when id=#{item.id} then #{item.status}
</foreach>
else default_value
</trim>

还有更常见的情况就是需要对要更新的数据进行判断,只有符合条件的数据才能进行更新,这种情况可以这么做:

<trim prefix="status =case" suffix="end,">
<foreach collection="list" item="item" index="index">
<if test="item.status !=null and item.status != -1">
when id=#{item.id} then #{item.status}
</if>
</foreach>
</trim>

这样的话只有要更新的list中status != null && status != -1的数据才能进行status更新.其他的将使用默认值更新,而不会保持原数据不变.如果要保持原数据不变呢?即满足条件的更新,不满足条件的保持原数据不变,简单的来做就是再加一个,因为mybatis中没有if...else...语法,但可以通过多个实现同样的效果,如下:

<trim prefix="status =case" suffix="end,">
<foreach collection="list" item="item" index="index">
<if test="item.status !=null and item.status != -1">
when id=#{item.id} then #{item.status}
</if>
<if test="item.status == null or item.status == -1">
when id=#{item.id} then mydata_table.status //这里就是原数据
</if>
</foreach>
</trim>

整体批量更新的写法如下:

<update id="updateBatch" parameterType="java.util.List">
update mydata_table
<trim prefix="set" suffixOverrides=",">
<trim prefix="status =case" suffix="end,">
<foreach collection="list" item="item" index="index">
<if test="item.status !=null and item.status != -1">
when id=#{item.id} then #{item.status}
</if>
<if test="item.status == null or item.status == -1">
when id=#{item.id} then mydata_table.status//原数据
</if>
</foreach>
</trim>
</trim>
where id in
<foreach collection="list" index="index" item="item" separator="," open="(" close=")">
#{item.id,jdbcType=BIGINT}
</foreach>
</update>

批量更新(单个字段,传参list),实际是sql批量更新的简化版本而已

单个字段

<update id="updateByBatch" parameterType="java.util.List">
update t_goods
set NODE_ID=
<foreach collection="list" item="item" index="index"
separator=" " open="case" close="end">
when GOODS_ID=#{item.goodsId} then #{item.nodeId}
</foreach>
where GOODS_ID in
<foreach collection="list" index="index" item="item"
separator="," open="(" close=")">
#{item.goodsId,jdbcType=BIGINT}
</foreach>
</update>

单个字段方法二

<update id="updateByBatch" parameterType="java.util.List">
UPDATE
t_goods
SET NODE_ID = CASE
<foreach collection="list" item="item" index="index">
WHEN GOODS_ID = #{item.goodsId} THEN #{item.nodeId}
</foreach>
END
WHERE GOODS_ID IN
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item.goodsId}
</foreach>
</update>

以上单字段更新实际执行:

UPDATE t_goods SET NODE_ID = CASE WHEN GOODS_ID = ? THEN ? END WHERE GOODS_ID IN ( ? )

sql批量更新(二)

传入的是List<Map<String,Object>>

直接运行插入,如果有插入的数据转为更新该条数据

<insert id="updateChartParamByAccountAndChartid">
insert into followme_parameters
(account,chart_id,signal_source,rate)
values
<foreach collection="list" separator="," index="index" item="item">
(#{item.account},#{item.chartId},#{item.signalSource},#{item.rate})
</foreach>
ON duplicate KEY UPDATE
signal_source=values(signal_source),rate=values(rate) </insert>

更新多条数据,更新的内容一样.

方法一,传map/ 传String

NODE_ID从map中取出来,goodsIdList是字符串拼接好的(如下面的"1,2,5")

<update id="updateByBatchPrimaryKey" parameterType="java.util.Map">
UPDATE t_goods
SET NODE_ID = #{nodeId}
WHERE GOODS_ID IN (${goodsIdList})
</update>

实际的sql

UPDATE t_goods SET NODE_ID = ? WHERE GOODS_ID IN (1,2,5);

方法二,传map/传list

NODE_ID从map中取出来,goodsIdList是用list拼接出来的

<update id="updateByBatchPrimaryKey" parameterType="java.util.Map">
UPDATE t_goods
SET NODE_ID = #{nodeId}
WHERE GOODS_ID IN
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item.goodsId}
</foreach>
</update>

实际的sql

UPDATE t_goods SET NODE_ID = ? WHERE GOODS_ID IN (1,2,5);

站在巨人的肩膀上摘苹果:

主力:https://blog.csdn.net/xyjawq1/article/details/74129316/

辅助:https://www.jianshu.com/p/041bec8ae6d3

Mybatis中进行批量更新(updateBatch)的更多相关文章

  1. mysql下的将多个字段名的值复制到另一个字段名中(批量更新数据)字符串拼接cancat实战例子

    mysql下的将多个字段名的值复制到另一个字段名中(批量更新数据)mysql字符串拼接cancat实战例子: mysql update set 多个字段相加,如果是数字相加可以直接用+号(注:hund ...

  2. Mybatis -- 批量更新 -- updateBatch

    mysql数据库配置: 数据库连接必须配置:&allowMultiQueries=true并且‘&’ 用&替换 jdbc.url=jdbc:mysql://192.168.10 ...

  3. Mybatis在oracle批量更新

    最近公司业务中为了提高效率要做mybatis批量更新,但是到了oracle数据库中做了好几次都没成功,后来发现mybatis最后少了个分号,可能是Mybatis内部做了异常try  catche  处 ...

  4. 关于mybatis中,批量增删改查以及參数传递的问题

    1.參数传递的问题 大多数情况下,我们都是利用map作为參数,而且大部分情况下都是仅仅有一个參数. 可是,我们也能够利用@param注解,来传入多个參数,此时,mybatis会自己主动将參数封装成ma ...

  5. Mybatis操作Mysql批量更新的一个坑-&allowMultiQueries=true允许批量更新

    前言            利用Mybatis批量更新或者批量插入,实际上即使Mybatis完美支持你的sql,你也得看看你操作的数据库是否完全支持,而同事,最近就遇到这样的一个坑! 问题 先带大家来 ...

  6. jdbctemplate中的批量更新使用,BigDecimal与造型的联系和区别

    //jdbctemplate批量新增的使用MENU_ID_LIST是前端页面传递到后端控制层,再由控制层传到实现层的List //JdbcTemplate是spring jdbctemplate通过注 ...

  7. Codeigniter 在Active Record中限制批量更新数目

    今天手头电商项目有个需求是:将订单中的优惠券自动发放给买家,所以要只更新优惠券表中的某几行数据,查了手册和网络都没有解决办法. 一开始用循环和遍历来做都是错的,因为update语句一下就更新掉所有符合 ...

  8. mybatis中批量更新的问题

    问题:使用mybatis在执批量更新操作时,一直报错执行失败 解决方法: 首先打印了SQL语句,发现SQL语句拿出来执行没问题,也可以批量执行.SQL没问题,应该是配置的问题. 在网上查询和很多资料, ...

  9. SpringBoot+Mybatis+Druid批量更新 multi-statement not allow异常

      本文链接:https://blog.csdn.net/weixin_43947588/article/details/90109325 注:该文是本博主记录学习之用,没有太多详细的讲解,敬请谅解! ...

随机推荐

  1. Sequence (矩阵快速幂+快速幂+费马小定理)

            Holion August will eat every thing he has found. Now there are many foods,but he does not wa ...

  2. Commando War (贪心)

    Waiting for orders we held in the wood, word from the front never came By evening the sound of the g ...

  3. 《Offer一箩筐》一份高质量「简历」撰写指南,望打扰!!

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」. 如果觉得 「不错」 的朋友,欢迎 「关注 + 留言 + 分享」,文末有完整的获取链接,您的支持是我前进的最大的动力! Hi~ 这里是 ...

  4. 还不懂Redis?看完这个故事就明白了!

    我是Redis 你好,我是Redis,一个叫Antirez的男人把我带到了这个世界上. 说起我的诞生,跟关系数据库MySQL还挺有渊源的. 在我还没来到这个世界上的时候,MySQL过的很辛苦,互联网发 ...

  5. 深入理解xLua热更新原理

    热更新简介 热更新是指在不需要重新编译打包游戏的情况下,在线更新游戏中的一些非核心代码和资源,比如活动运营和打补丁.热更新分为资源热更新和代码热更新两种,代码热更新实际上也是把代码当成资源的一种热更新 ...

  6. [程序员代码面试指南]递归和动态规划-数字字符串转换为字母组合的种数(DP)

    题意 给一个字符串,只由数字组成,若是'1'-'26',则认为可以转换为'a'-'z'对应的字母,问有多少种转换方法. 题解 状态转移很好想,注意dp多开一位,dp[0]为dp[2]的计算做准备.dp ...

  7. 【好消息】博客迁移到github,求关注,求star,求支持

    博客迁移到github 地址:https://github.com/dirkhe1051931999/hjBlog

  8. day52:django:ORM单表/多表操作

    目录 1.ORM 2.ORM单表增删改查 13个必知必会的查询接口 filter基于双下划线的模糊查询 3.ORM多表增删改查 ORM 什么是ORM? ORM(object relational ma ...

  9. SessionMiddleware源码分析

    settings.py文件中 MIDDLEWARE = [ 'django.contrib.sessions.middleware.SessionMiddleware', ] # from djang ...

  10. JVM学习(七)JMM内存模型

    一.什么是JMM 概念:Java内存模型(Java Memory Model ,JMM)就是一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,保证了Java程序在各种平台下对内存的访问都能 ...