Fluent Mybatis 批量更新的使用

目录
  • 批量更新同一张表的数据
    • 更新多条数据,每条数据都不一样
  • java中for循环实现方式
  • 一条SQL,服务端逐条更新
    • mybatis实现方式
  • 使用FluentMybatis实现方式
  • 使用mysql的Case When then方式更新
    • mybatis原生实现方式
  • 批量更新不同的表数据
  • 参考

批量更新同一张表的数据

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

背景描述

通常需要一次更新多条数据有两个方式

在业务代码中循环遍历,逐条更新
一次性更新所有数据, 采用批量sql方式,一次执行。

更准确的说是一条sql语句来更新所有数据,逐条更新的操作放到数据库端,在业务代码端展现的就是一次性更新所有数据。

这两种方式各有利弊,程序中for循环实现就不说了,这里主要介绍第二种方式在fluent mybatis中的实现,以及和mybatis实现的对比。

java中for循环实现方式

public class UpdateBatchTest extends BaseTest {
    @Autowired
    private StudentMapper mapper;

    @Test
    public void testBatchJavaEach() {
        /** 构造多个更新 **/
        List<IUpdate> updates = this.newListUpdater();
        for (IUpdate update : updates) {
            mapper.updateBy(update);
        }
    }

    /**
     * 构造多个更新操作
     */
    private List<IUpdate> newListUpdater() {
        StudentUpdate update1 = new StudentUpdate()
            .update.userName().is("user name23").end()
            .where.id().eq(23L).end();
        StudentUpdate update2 = new StudentUpdate()
            .update.userName().is("user name24").end()
            .where.id().eq(24L).end();
        return Arrays.asList(update1, update2);
    }
}

这种方式在大批量更新时, 最大的问题就是效率,逐条更新,每次都会连接数据库,然后更新,再释放连接资源。

一条SQL,服务端逐条更新

mybatis实现方式

通过mybatis提供的循环标签,一次构造多条update的sql,一次提交服务器进行执行。

<update id="updateStudentBatch"  parameterType="java.util.List">
    <update id="updateStudentBatch"  parameterType="java.util.List">
        <foreach collection="list" item="item" index="index" open="" close="" separator=";">
            update student
            <set>
                user_name=#{item.userName}
            </set>
            where id = #{item.id}
        </foreach>
    </update>
</update>

定义Mapper

public interface StudentBatchMapper {
    void updateStudentBatch(List list);
}

执行测试验证

public class UpdateBatchTest extends BaseTest {
    @Autowired
    private StudentBatchMapper batchMapper;

    @Test
    public void updateStudentBatch() {
        List<StudentEntity> students = Arrays.asList(
            new StudentEntity().setId(23L).setUserName("user name23"),
            new StudentEntity().setId(24L).setUserName("user name24"));
        batchMapper.updateStudentBatch(students);
        /** 验证SQL参数 **/
        db.table(ATM.table.student).query().eqDataMap(ATM.dataMap.student.table(2)
            .id.values(23L, 24L)
            .userName.values("user name23", "user name24")
        );
    }
}

使用FluentMybatis实现方式

使用fluent mybatis进行批量更新很简单,只需要在#updateBy方法中传入 IUpdate数组即可

public class UpdateBatchTest extends BaseTest {
    @Autowired
    private StudentMapper mapper;

    @DisplayName("批量更新同一张表")
    @Test
    public void testUpdateBatch_same() {
        IUpdate[] updates = this.newListUpdater().toArray(new IUpdate[0]);
        mapper.updateBy(updates);
        /** 验证SQL语句 **/
        db.sqlList().wantFirstSql().eq("" +
                "UPDATE student SET gmt_modified = now(), user_name = ? WHERE id = ?; " +
                "UPDATE student SET gmt_modified = now(), user_name = ? WHERE id = ?"
            , StringMode.SameAsSpace);
        /** 验证SQL参数 **/
        db.table(ATM.table.student).query().eqDataMap(ATM.dataMap.student.table(2)
            .id.values(23L, 24L)
            .userName.values("user name23", "user name24")
        );
    }
}

要实现批量更新,首先得设置mysql支持批量操作,在jdbc url链接中附加&allowMultiQueries=true属性

例如:

jdbc:mysql://localhost:3306/testdb?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true

使用mysql的Case When then方式更新

UPDATE student
SET gmt_modified = now(),
address = case id when 1 then 'address 1' when 2 then 'address 2' when 3 then 'address 3' end
WHERE id in (1, 2, 3)

上面的sql语句使用mysql的case when then语法实现的批量更新3条记录,并且根据id的值不同,设置不同的address值。

mybatis原生实现方式

如果使用mybatis的xml语法来实现,xml文件就需要表达为下面方式:

xml文件

<update id="updateBatchByIds" parameterType="list">
    update student
    <trim prefix="set" suffixOverrides=",">
        <trim prefix="address =case id" suffix="end,">
            <foreach collection="list" item="item" index="index">
                <if test="item.id!=null">
                    when #{item.id} then #{item.address}
                </if>
            </foreach>
        </trim>
    </trim>
    <trim prefix="age =case id" suffix="end,">
        <foreach collection="list" item="item" index="index">
            <if test="item.id!=null">
                when #{item.id} then #{item.age}
            </if>
        </foreach>
    </trim>
    where id in
    <foreach collection="list" item="item" index="index" separator="," open="(" close=")">
        #{item.id}
    </foreach>
</update>

定义Mapper

public interface StudentBatchMapper {
    int updateBatchByIds(List<StudentEntity> list);
}

验证

public class CaseFuncTest extends BaseTest {
    @Autowired
    private StudentBatchMapper batchMapper;

    @Test
    public void test_mybatis_batch() {
        batchMapper.updateBatchByIds(Arrays.asList(
            new StudentEntity().setId(1L).setAddress("address 1").setAge(23),
            new StudentEntity().setId(2L).setAddress("address 2").setAge(24),
            new StudentEntity().setId(3L).setAddress("address 3").setAge(25)
        ));
        /** 验证执行的SQL语句 **/
        db.sqlList().wantFirstSql().eq("" +
                "update student " +
                "set address =case id when ? then ? when ? then ? when ? then ? end, " +
                "age =case id when ? then ? when ? then ? when ? then ? end " +
                "where id in ( ? , ? , ? )"
            , StringMode.SameAsSpace);
    }
}

使用Fluent Mybatis实现方式

public class CaseFuncTest extends BaseTest {
    @Autowired
    private StudentMapper mapper;

    @Test
    public void test_fluentMybatisBatch() throws Exception {
        final String CaseWhen = "case id " +
            "when 1 then ? " +
            "when 2 then ? " +
            "else ? end";
        StudentUpdate update = new StudentUpdate()
            .update.address().applyFunc(CaseWhen, "address 1", "address 2", "address 3")
            .set.age().applyFunc(CaseWhen, 23, 24, 25)
            .end()
            .where.id().in(new int[]{1, 2, 3}).end();
        mapper.updateBy(update);
        /** 验证执行的SQL语句 **/
        db.sqlList().wantFirstSql()
            .eq("UPDATE student " +
                    "SET gmt_modified = now(), " +
                    "address = case id when 1 then ? when 2 then ? else ? end, " +
                    "age = case id when 1 then ? when 2 then ? else ? end " +
                    "WHERE id IN (?, ?, ?)",
                StringMode.SameAsSpace);
    }
}

只需要在applyFunc中传入case when语句,和对应的参数(对应case when语句中的预编译占位符'?')

如果业务入口传入的是Entity List或者Map List,可以使用java8的stream功能处理成数组,示例如下:

public class CaseFuncTest extends BaseTest {
    @Autowired
    private StudentMapper mapper;

    @Test
    public void test_fluentMybatisBatch2() throws Exception {
        List<StudentEntity> students = Arrays.asList(
            new StudentEntity().setId(1L).setAddress("address 1").setAge(23),
            new StudentEntity().setId(2L).setAddress("address 2").setAge(24),
            new StudentEntity().setId(3L).setAddress("address 3").setAge(25));
        final String CaseWhen = "case id " +
            "when 1 then ? " +
            "when 2 then ? " +
            "else ? end";
        StudentUpdate update = new StudentUpdate()
            .update.address().applyFunc(CaseWhen, getFields(students, StudentEntity::getAddress))
            .set.age().applyFunc(CaseWhen, getFields(students, StudentEntity::getAge))
            .end()
            .where.id().in(getFields(students, StudentEntity::getId)).end();
        mapper.updateBy(update);
        // 验证SQL语句
        db.sqlList().wantFirstSql()
            .eq("UPDATE student " +
                    "SET gmt_modified = now(), " +
                    "address = case id when 1 then ? when 2 then ? else ? end, " +
                    "age = case id when 1 then ? when 2 then ? else ? end " +
                    "WHERE id IN (?, ?, ?)",
                StringMode.SameAsSpace);
        // 验证参数
        db.sqlList().wantFirstPara()
            .eqReflect(new Object[]{"address 1", "address 2", "address 3", 23, 24, 25, 1L, 2L, 3L});
    }

    private Object[] getFields(List<StudentEntity> students, Function<StudentEntity, Object> getField) {
        return students.stream().map(getField).toArray(Object[]::new);
    }
}

使用Fluent Mybatis无需额外编写xml文件和mapper(使用框架生成的Mapper文件就够了)。在业务逻辑上不至于因为有额外的xml文件,而产生割裂感。

批量更新不同的表数据

上面的例子使用mybatis和fluent mybatis演示的如果通过不同方法批量更新同一张表的数据,在fluent mybatis的更新其实不限定于同一张表,

在#updateBy(IUpdate... updates)函数可以传入任意表更新.

public class UpdateBatchTest extends BaseTest {
    @Autowired
    private StudentMapper mapper;

    @DisplayName("批量更新不同表")
    @Test
    public void testUpdateBatch_different() {
        StudentUpdate update1 = new StudentUpdate()
            .update.userName().is("user name23").end()
            .where.id().eq(23L).end();
        HomeAddressUpdate update2 = new HomeAddressUpdate()
            .update.address().is("address 24").end()
            .where.id().eq(24L).end();

        /** 执行不同表的批量更新 **/
        mapper.updateBy(update1, update2);

        /** 验证实际执行的预编译SQL语句**/
        db.sqlList().wantFirstSql().eq("" +
                "UPDATE student SET gmt_modified = now(), user_name = ? WHERE id = ?; " +
                "UPDATE home_address SET gmt_modified = now(), address = ? WHERE id = ?", StringMode.SameAsSpace);
        db.table(ATM.table.student).query().eqDataMap(ATM.dataMap.student.table(2)
            .id.values(23L, 24L)
            .userName.values("user name23", "user")
        );
        /** 验证实际执行预编译SQL入参值 **/
        db.table(ATM.table.homeAddress).query().eqDataMap(ATM.dataMap.homeAddress.table(2)
            .id.values(23, 24)
            .address.values("address", "address 24")
        );
    }
}

示例更新了2张表: student 和 home_address

参考

Fluent MyBatis地址
Fluent MyBatis文档

到此这篇关于Fluent Mybatis 批量更新的使用的文章就介绍到这了,更多相关Fluent Mybatis 批量更新内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Fluent Mybatis,原生Mybatis,Mybatis Plus三者功能对比

    目录 三者实现对比 使用fluent mybatis 来实现上面的功能 换成mybatis原生实现效果 换成mybatis plus实现效果 生成代码编码比较 fluent mybatis生成代码设置 mybatis plus代码生成设置 FluentMybatis特性一览 三者对比总结 Fluent Mybatis介绍和源码 使用fluent mybatis可以不用写具体的xml文件,通过java api可以构造出比较复杂的业务sql语句,做到代码逻辑和sql逻辑的合一. 不用再需要在Dao中

  • Fluent Mybatis零xml配置实现复杂嵌套查询

    目录 嵌套查询 in (select 子查询) exists (select子查询) 嵌套查询 使用Fluent Mybatis, 不用手写一行xml文件或者Mapper文件,在dao类中即可使用java api构造中比较复杂的嵌套查询. 让dao的代码逻辑和sql逻辑合二为一. 前置准备,maven工程设置 参考文章 使用FluentMybatis实现mybatis动态sql拼装和fluent api语法 in (select 子查询) 嵌套查询表和主查询表一样的场景 .column().in

  • Fluent Mybatis让你摆脱Xml文件的技巧

    目录 一.啥是Fluent-Mybatis 二.SpringBoot + Fluent-Mybatis 三.官方链接 一.啥是Fluent-Mybatis 与Mybatis-Plus类似,是对Mybaits进一步的封装,使之语法简洁明了,更重要的是不需要在自主创建Xml文件,可以只用一个实体类对象,通过代码生成器,在编译的过程中生成所需要的各类文件,简化了项目的基础构建,提高开发效率. 二.SpringBoot + Fluent-Mybatis 1.创建数据库测试表 DROP TABLE IF

  • Fluent MyBatis实现动态SQL

    目录 数据准备 代码生成 在 WHERE 条件中使用动态条件 在 UPDATE 使用动态更新 choose 标签 参考 MyBatis 令人喜欢的一大特性就是动态 SQL.在使用 JDBC 的过程中, 根据条件进行 SQL 的拼接是很麻烦且很容易出错的, MyBatis虽然提供了动态拼装的能力,但这些写xml文件,也确实折磨开发.Fluent MyBatis提供了更贴合Java语言特质的,对程序员友好的Fluent拼装能力. Fluent MyBatis动态SQL,写SQL更爽 数据准备 为了后

  • Fluent Mybatis如何做到代码逻辑和sql逻辑的合一

    使用fluent mybatis可以不用写具体的xml文件,通过java api可以构造出比较复杂的业务sql语句,做到代码逻辑和sql逻辑的合一.不再需要在Dao中组装查询或更新操作,在xml或mapper中再组装参数.那对比原生Mybatis, Mybatis Plus或者其他框架,FluentMybatis提供了哪些便利呢? 场景需求设置 我们通过一个比较典型的业务需求来具体实现和对比下,假如有学生成绩表结构如下: create table `student_score` ( id big

  • FluentMybatis快速入门详细教程

    使用fluent mybatis可以不用写具体的xml文件,通过java api可以构造出比较复杂的业务sql语句,做到代码逻辑和sql逻辑的合一. 不再需要在Dao中组装查询或更新操作,在xml或mapper中再组装参数. 对底层数据表关联关系的处理,我们总是绕不开什么一对一,一对多,多对多这里比较烦人的关系. 业界优秀的ORM框架也都给出了自己的答案,简单来说就以下几种方式: hibernate和JPA对开发基本屏蔽了底层数据的处理,只需要在model层设置数据级联关系即可.但这种设置也往往

  • springboot 整合fluent mybatis的过程,看这篇够了

    1.导入pom依赖 <!-- mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version> </dependency> <!--mysql依赖--> <de

  • Fluent Mybatis实际开发中的优势对比

    之前文章介绍过了Fluent基本框架等,其中有几个重要的方法用到了IQuery和IUpdate对象. 这2个对象是FluentMybatis实现复杂和动态sql的构造类,通过这2个对象fluent mybatis可以不用写具体的xml文件, 直接通过java api可以构造出比较复杂的业务sql语句,做到代码逻辑和sql逻辑的合一.下面接着介绍如何通过IQuery和IUpdate定义强大的动态SQL语句. 表结构 假如有学生成绩表结构如下: create table `student_score

  • FluentMybatis实现mybatis动态sql拼装和fluent api语法

    目录 开始第一个例子: Hello World 新建演示用的数据库结构 创建数据库表对应的Entity类 运行测试来见证Fluent Mybatis的神奇 配置spring bean定义 使用Junit4和Spring-test来执行测试 开始第一个例子: Hello World 新建Java工程,设置maven依赖 新建maven工程,设置项目编译级别为Java8及以上,引入fluent mybatis依赖包. <dependencies> <!-- 引入fluent-mybatis

  • Fluent Mybatis 批量更新的使用

    目录 批量更新同一张表的数据 更新多条数据,每条数据都不一样 java中for循环实现方式 一条SQL,服务端逐条更新 mybatis实现方式 使用FluentMybatis实现方式 使用mysql的Case When then方式更新 mybatis原生实现方式 批量更新不同的表数据 参考 批量更新同一张表的数据 更新多条数据,每条数据都不一样 背景描述 通常需要一次更新多条数据有两个方式 在业务代码中循环遍历,逐条更新 一次性更新所有数据, 采用批量sql方式,一次执行. 更准确的说是一条s

  • Mybatis批量更新报错问题

    下面给大家介绍mybatis批量更新报错问题, allowMultiQueries=true 后来发现是jdbc链接没有加允许批量更新操作的参数引起的,不加会报badsql,mysql版的mybatis批量更新操作如下 <update id="updateOrderOverdueStatus" parameterType="java.util.List"> <foreach collection="list" item=&quo

  • 解决mybatis批量更新(update foreach)失败的问题

    如下所示: <!--批量更新报表 --> <update id="updateIssueByBatch" parameterType="java.util.List"> <foreach collection="issueList" item="item" index="index" separator=";"> update sys_issue &l

  • Mybatis 批量更新实体对象方式

    目录 Mybatis批量更新实体对象 (1)Dao层接口 (2)Mapper.xml 文件 Mybatis批量更新数据三种方法效率对比 探讨批量更新数据三种写法的效率问题 Mybatis批量更新实体对象 (1)Dao层接口 /** * 根据更新采购计划(批量) * @param plans */ void batchUpdatePlan(List<PubPurchasePlan> plans); (2)Mapper.xml 文件 <sql id="batchUpdatePlan

  • 解决mybatis批量更新出现SQL报错问题

    一.问题重现 1.配置文件 spring: #DataSource数据源 datasource: url: jdbc:mysql://127.0.0.1:3306/mybatis_test?useSSL=false&amp username: root password: root driver-class-name: com.mysql.jdbc.Driver #MyBatis配置 mybatis: type-aliases-package: com.hl.mybatis.pojo #别名定义

  • 详解mybatis 批量更新数据两种方法效率对比

    上节探讨了批量新增数据,这节探讨批量更新数据两种写法的效率问题. 实现方式有两种, 一种用for循环通过循环传过来的参数集合,循环出N条sql, 另一种 用mysql的case when 条件判断变相的进行批量更新 下面进行实现. 注意第一种方法要想成功,需要在db链接url后面带一个参数  &allowMultiQueries=true 即:  jdbc:mysql://localhost:3306/mysqlTest?characterEncoding=utf-8&allowMulti

  • Mybatis批量更新三种方式的实现

    Mybatis实现批量更新操作 方式一: <update id="updateBatch" parameterType="java.util.List"> <foreach collection="list" item="item" index="index" open="" close="" separator=";">

  • Mybatis批量插入更新xml方式和注解方式的方法实例

    前言 最近工作上遇到很多批量插入的场景,但是百度很难得到我想要的结果,而且查出来的效果不是很好- 所以就自己来写一份给大家参考,希望对大家有用 Mybatis 批量插入注解形式 @Insert("<script> INSERT INTO t_device_policy " + "(id,device_id,type,policy,create_time,update_time) " + "VALUES " + "<fo

  • 详解扩展tk.mybatis的批量更新的功能

    tk.mybatis没有带批量更新的功能,批量更新却是经常使用的,所以需要自己实现. 批量更新网上主要有2种方式:case when方式.foreach方式 但是foreachzhe这种方式效率非常低下,不知道为何那多么帖子在流传,请看我另一个文章. 扩展tk.mybatis的批量更新,采用case when方式,源码干货如下: 首先定义下mapper接口 import org.apache.ibatis.annotations.UpdateProvider; import java.util.

  • mybatis执行update批量更新时报错的解决方案

    目录 执行update批量更新时报错 在使用Mybatis批量更新时 定义Mapper Dao接口中定义 最后在service中调用 同时执行多条sql的办法 执行update失败问题 说下原因 解决办法 执行update批量更新时报错 在使用Mybatis 批量更新时 想要批量更新时通常在mapper中这么写: 定义Mapper  Dao接口中定义 最后在service中调用 生成的sql直接放到mysql中运行完全没有问题,但是mybatis执行的时候却会报错: <span style=&quo

随机推荐