那些年在mybatis中批量操作

116 阅读3分钟

一、背景

在mybatis框架中,我们针对大量数据操作,会采用批量操作的方式,让我们一起总结一些常见的批量操作形式吧,以下从增,改操作来叙述。

1、环境:

jdk1.8、maven

pom.xml

<!-- Mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.5</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.1</version>
</dependency>
<dependency>
    <groupId>com.github.miemiedev</groupId>
    <artifactId>mybatis-paginator</artifactId>
    <version>1.2.15</version>
</dependency>
<!-- MySql -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.20</version>
</dependency>
<!-- 连接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.0.9</version>
</dependency>

2、表

CREATE TABLE `t_company_user_rel` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `company_id` bigint unsigned NOT NULL COMMENT '公司ID',
  `user_id` bigint unsigned NOT NULL COMMENT '用户ID',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime NOT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_user_id` (`user_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='用户与公司关系表';

CREATE TABLE `t_member` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `file_number` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '文件编号',
  `name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '姓名',
  `sex` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '性别',
  `id_card` varchar(18) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '身份证',
  `phone_number` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '电话号码',
  `reg_time` date DEFAULT NULL COMMENT '注册时间',
  `password` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '密码',
  `email` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '电子邮箱',
  `birthday` date DEFAULT NULL COMMENT '生日',
  `remark` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=93 DEFAULT CHARSET=utf8mb3;

3、 domain

public class CompanyUserRel implements Serializable {
    /**
     * 主键ID
     *
     * @mbg.generated
     */
    private Long id;

    /**
     * 公司ID
     *
     * @mbg.generated
     */
    private Long companyId;

    /**
     * 用户ID
     *
     * @mbg.generated
     */
    private Long userId;

    /**
     * 创建时间
     *
     * @mbg.generated
     */
    private Date createTime;

    /**
     * 更新时间
     *
     * @mbg.generated
     */
    private Date updateTime;

    private static final long serialVersionUID = 1L;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getCompanyId() {
        return companyId;
    }

    public void setCompanyId(Long companyId) {
        this.companyId = companyId;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", id=").append(id);
        sb.append(", companyId=").append(companyId);
        sb.append(", userId=").append(userId);
        sb.append(", createTime=").append(createTime);
        sb.append(", updateTime=").append(updateTime);
        sb.append(", serialVersionUID=").append(serialVersionUID);
        sb.append("]");
        return sb.toString();
    }
}


public class Member implements Serializable {
    private Integer id;

    private String fileNumber;

    private String name;

    private String sex;

    private String idCard;

    private String phoneNumber;

    private Date regTime;

    private String password;

    private String email;

    private Date birthday;

    private String remark;

    private static final long serialVersionUID = 1L;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getFileNumber() {
        return fileNumber;
    }

    public void setFileNumber(String fileNumber) {
        this.fileNumber = fileNumber;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getIdCard() {
        return idCard;
    }

    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public Date getRegTime() {
        return regTime;
    }

    public void setRegTime(Date regTime) {
        this.regTime = regTime;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", id=").append(id);
        sb.append(", fileNumber=").append(fileNumber);
        sb.append(", name=").append(name);
        sb.append(", sex=").append(sex);
        sb.append(", idCard=").append(idCard);
        sb.append(", phoneNumber=").append(phoneNumber);
        sb.append(", regTime=").append(regTime);
        sb.append(", password=").append(password);
        sb.append(", email=").append(email);
        sb.append(", birthday=").append(birthday);
        sb.append(", remark=").append(remark);
        sb.append(", serialVersionUID=").append(serialVersionUID);
        sb.append("]");
        return sb.toString();
    }
}

二、增

Mybatis在插入单条数据的时候有两种方式返回自增主键:

1、对于支持生成自增主键的数据库:增加 useGenerateKeys和keyProperty ,标签属性。

2、不支持生成自增主键的数据库:使用selectKey标签。

从官网资料可以看出Mybatis是支持批量插入时返回自增主键的。

但是在开发过程中如果遇到返回自增id失效情况,可以从以下方面排查问题:

1、Mybatis版本至少3.3.1以上。

2、在Mapper文件中,方法参数不能使用@Param注解。

3、Mapper.xml文件中,标签上指定参数类型(parameterType=“java.util.List”),设置useGeneratedKeys=“true”,keyProperty=“id”(list中元素的主键)。

1、除主键之外,无其它唯一索引限制的批量插入

<insert id="batchInsert" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
    insert into t_member (file_number, name, sex,
    id_card, phone_number, reg_time,
    password, email, birthday,
    remark)
    VALUES
    <foreach collection="list" item="item" separator=",">
        (#{item.fileNumber,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR}, #{item.sex,jdbcType=VARCHAR},
        #{item.idCard,jdbcType=VARCHAR}, #{item.phoneNumber,jdbcType=VARCHAR}, #{item.regTime,jdbcType=DATE},
        #{item.password,jdbcType=VARCHAR}, #{item.email,jdbcType=VARCHAR}, #{item.birthday,jdbcType=DATE},
        #{item.remark,jdbcType=VARCHAR})
    </foreach>
</insert>

2、唯一键与主键同时存在的批量插入

<insert id="batchInsertOrUpdate" parameterType="java.util.List">
    insert into t_company_user_rel (company_id, user_id, create_time,update_time) values
    <foreach collection="list" separator="," item="item">
        (#{item.companyId,jdbcType=BIGINT}, #{item.userId,jdbcType=BIGINT}, #{item.createTime,jdbcType=TIMESTAMP},
        #{item.updateTime,jdbcType=TIMESTAMP})
    </foreach>
    ON DUPLICATE KEY UPDATE
    company_id=VALUES(company_id),update_time=VALUES(update_time)
</insert>  

三、改

1、case...when 组合更新

<update id="batchCaseWhenUpdate" parameterType="java.util.List">
    UPDATE t_member
    <trim prefix="set" suffixOverrides=",">
        <trim prefix="name =case" suffix="end,">
            <foreach collection="list" item="item">
                when id=#{item.id} then #{item.name}
            </foreach>
        </trim>
        <trim prefix="password =case" suffix="end,">
            <foreach collection="list" item="item">
                when id=#{item.id} then #{item.password}
            </foreach>
        </trim>
    </trim>
    WHERE id IN
    <foreach collection="list" item="item" separator="," open="(" close=")">
        #{item.id,jdbcType=BIGINT}
    </foreach>
</update>
    

2、sql批量更新

<update id="batchSqlUpdate" parameterType="java.util.List">
 <foreach collection="list" item="item" separator=";">
     UPDATE t_member
     SET name=#{item.name},password=#{item.password}
     WHERE id=#{item.id}
 </foreach>
</update>

注意: 组装多个update语句,这种方式需要设置jdbc连接 allowMultiQueries=true

四、参考博客

1、blog.csdn.net/johnny0316/…

2、blog.csdn.net/weixin_4292…