Java--MyBatis批量插入批量更新和批量删除

Posted MinggeQingchun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java--MyBatis批量插入批量更新和批量删除相关的知识,希望对你有一定的参考价值。

MyBatis批量插入数据
[Mybatis 插入与批量插入以及多参数批量删除]
(http://www.cnblogs.com/liaojie970/p/5577018.html)
注意项:需要注意id是varchar类型还是bigint/int类型

1、批量插入

WaterEleMapper.xml部分代码

<!--批量增加测试-->
    <insert id="insertList" parameterType="java.util.List">
        insert into t_enterprise_water_ele
        (
        /*方法一*/
        -- WATER_ELE_ID,
        -- ENTERPRISE_ID,
        -- ENTERPRISE_USCC,
        -- ENTERPRISE_NAME,
        -- YEARMONTH,
        -- WATER_SIZE,
        -- WATER_AMOUNT,
        -- ELE_SIZE,
        -- ELE_AMOUNT,
        -- STATUS,
        -- OPERATOR,
        -- OPERATE_TIME
        /*方法二*/
        <include refid="Base_Column_List"/>
        )
        VALUES
        <foreach collection="list" item="item" index="index" separator=",">
            (
            #{item.waterEleId,jdbcType=VARCHAR},
            #{item.enterpriseId,jdbcType=VARCHAR},
            #{item.enterpriseUscc,jdbcType=VARCHAR},
            #{item.enterpriseName,jdbcType=VARCHAR},
            #{item.yearmonth,jdbcType=VARCHAR},
            #{item.waterSize,jdbcType=DECIMAL},
            #{item.waterAmount,jdbcType=VARCHAR},
            #{item.eleSize,jdbcType=DOUBLE},
            #{item.eleAmount,jdbcType=VARCHAR},
            #{item.status,jdbcType=INTEGER},
            #{item.operator,jdbcType=VARCHAR},
            #{item.operateTime,jdbcType=TIMESTAMP}
            )
        </foreach>
    </insert>

xxxMapper部分代码

int insertList(List<WaterEle> list);

想要实现批量更新我们就需要使用到for each标签

对于foreach标签的解释参考了网上的资料,具体如下:
1、foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。
2、foreach元素的属性主要有 item,index,collection,open,separator,close
(1)item 表示集合中每一个元素进行迭代时的别名
(2)index 指定一个名字,用于表示在迭代过程中,每次迭代到的位置
(3)open 表示该语句以什么开始
(4)separator 表示在每次进行迭代之间以什么符号作为分隔 符
(5)close 表示以什么结束

在使用for each的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况 下,该属性的值是不一样的,主要有一下3种情况:
(1)如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
(2)如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
(3)如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map


使用批量插入执行的SQL语句应该等价于:

insert into redeem_code (batch_id, code, type, facevalue,create_user,create_time)
values (?,?,?,?,?,? ),(?,?,?,?,?,? ),(?,?,?,?,?,? ),(?,?,?,?,?,? )

2、批量更新
mybatis 实现批量更新

1、传list集合
单个字段

  批量更新测试
  <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 ( ? )

多个字段

<update id="updateBatch" parameterType="java.util.List">
    update t_user
    <trim prefix="set" suffixOverrides=",">
        <trim prefix="STATUS =case" suffix="end,">
            <foreach collection="list" item="i" index="index">
                <if test="i.status!=null">
                    when USER_ID=#{i.userId} then #{i.status}
                </if>
            </foreach>
        </trim>
        <trim prefix=" OPERATE_TIME =case" suffix="end,">
            <foreach collection="list" item="i" index="index">
                <if test="i.operateTime!=null">
                    when USER_ID=#{i.userId} then #{i.operateTime}
                </if>
            </foreach>
        </trim>

        <trim prefix="OPERATOR =case" suffix="end," >
            <foreach collection="list" item="i" index="index">
                <if test="i.operator!=null">
                    when USER_ID=#{i.userId} then #{i.operator}
                </if>
            </foreach>
        </trim>
    </trim>
    where
    <foreach collection="list" separator="or" item="i" index="index" >
        USER_ID=#{i.userId}
    </foreach>
</update>
 int updateBatch(List<WaterEle> list);

更新多条记录的同一个字段为同一个值

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

2、传map/ 传String(同批量删除的"传map/ 传String")

<update id="deleteByPrimaryKey" parameterType="java.util.Map">
    UPDATE t_order_checkout
    SET NODE_ID = #{nodeId, jdbcType=VARCHAR}, OPERATOR = #{operator, jdbcType=VARCHAR}
    WHERE CHECKOUT_ID IN (${checkoutIdList})
</update>

3、批量删除(数组)

1、传数组

int deleteByBatch(String[] array);
    <delete id="deleteByBatch" parameterType="java.lang.String">
        delete from t_enterprise_output_value
        where OUTPUT_ID IN
        <foreach collection="array" item="outputId" open="(" separator="," close=")">
            #{outputId}
        </foreach>
    </delete>

2、传map / 传String

<delete id="deleteByRole" parameterType="java.util.Map">
        DELETE
        FROM
        t_user_role
        <where>
            <if test="userIdList != null">
                USER_ID IN (#{userIdList,jdbcType=VARCHAR})
            </if>
            <if test="roleId != null">
                AND ROLE_ID=#{roleId,jdbcType=VARCHAR}
            </if>
            <if test="sysCode != null">
                AND SYSCODE=#{sysCode}
            </if>
        </where>
    </delete>

因为表中没有fileIds字段,所以如果传map进入的话,需要在map中定义该字段

map.put("fileIds","1,2,3"); 
//美元符$直接注入
<delete id="deleteByPrimaryKey" parameterType="java.util.Map">
    DELETE FROM t_attachment WHERE FILE_ID  IN (${fileIds})
</delete>

完整的sql语句是:DELETE FROM t_attachment WHERE FILE_ID IN (1,2,3),适用于表中该字段是int或者bigint类型,不适用于varchar。如果该字段是varchar类型,则正确的sql语句应该是:DELETE FROM t_attachment WHERE FILE_ID IN ("1","2","3");
map中就应该这样定义了:

 数组/集合 -->(1,2,3,4)
 String userIdList = formData.get("userIdList");
 String[] users = userIdList.split(",");
 String str = "";
 for (String user : users) {
     str += "\\"" + user + "\\"" + ",";
 }
 String substring = str.substring(0, str.lastIndexOf(","));
 System.out.println(substring);

如果要传substring进sql语句中,但是substring不是数据库表中的字段,
三种方法:
① map.put("substring",substring),sql接收参数parameterType传java.util.Map
② 将substring放入对象中,传对象进去
③ 使用@Param("substring")注解
int deleteByCheckoutId(@Param("checkoutIdList") String checkoutIdList);

int deleteByCheckoutId(long cDetailId);不需要注解是因为cDetailId对应表中的C_DETAIL_ID,因为是表中现存的所以可以不用加,我个人理解。

<delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
    delete from t_checkout_detail
    where C_DETAIL_ID = #{cDetailId,jdbcType=BIGINT}
</delete>

3、多参数批量删除示例
如果删除不是以主键为条件,而是多个条件同时成立才可以删除

<delete id="deleteByUserIdSysRoleBatch">
    delete from t_user_role
    where SYSCODE = #{sysCode,jdbcType=VARCHAR} AND ROLE_ID = #{roleId,jdbcType=VARCHAR} AND USER_ID IN
    <foreach collection="userIds" item="item" index="index" open="(" separator="," close=")">
        #{item}
    </foreach>
</delete>

control层接口

    @RequestMapping(value = "", method = RequestMethod.POST)
    public ResponseObj<Boolean> setMoreUserToRole(@RequestBody Map<String, String> formData) {

        String userIdList = formData.get("userIdList");
        String[] users = userIdList.split(",");
        String str = "";
        for (String user : users) {
            str += "\\"" + user + "\\"" + ",";
        }
        String substring = str.substring(0, str.lastIndexOf(","));
        System.out.println(substring);

        String sysCode = formData.get("sysCode");
        String roleId1 = formData.get("roleId");
        userRoleMapper.deleteByUserIdSysRoleBatch(sysCode, roleId1, users);

        List<UserRole> list = new ArrayList<>();
        for (int i = 0; i < users.length; i++) {
            UserRole userRole = new UserRole();
            String roleId = formData.get("roleId");
            if (roleId != null && !"".equals(roleId)) {
                userRole.setRoleId(roleId);
            }
            userRole.setStatus(SysData.STATUS_NORMAL);
            userRole.setOperateTime(DateUtil.getDateTime());
            userRole.setOperator(formData.get("operator"));
            userRole.setSysCode(formData.get("sysCode"));
            userRole.setId(CommonUtil.getSysRef());
            userRole.setUserId(users[i]);

            list.add(userRole);
        }

        int i = userRoleMapper.addByBatch(list);
        if (i == users.length)
            return new ResponseObj<Boolean>(true, RetCode.SUCCESS);
        return new ResponseObj<Boolean>(false, RetCode.FAIL);
    }
int deleteByUserIdSysRoleBatch(@Param("sysCode") String sysCode, 
                               @Param("roleId") String roleId,
                               @Param("userIds") String[] userId);

上述collection的值为ids,是传入的参数Map的key

4、批量查询

1、orderList可以使用map/String传入

<select id="selectOrder" parameterType="java.util.Map" resultMap="OrderMap">
    SELECT * FROM t_ WHERE ORDER_ID in (${orderList})
</select>

对于表中的主键是bigint / int

==>  Preparing: SELECT * FROM t_order WHERE ORDER_ID in (?) 
==> Parameters: 1,2,5(String)
<==    Columns: ORDER_ID, GOODS_ID, UNIT_PRICE, SOLD_NUM, ORDER_STATUS, OPERATOR, OPERATE_TIME
<==        Row: 1, 356346093, 43.00, 3, 109002, yyadmin, 2017-12-16 21:01:20.0
<==      Total: 1

注意"1,2,5"传过来的是String类型,实际sql语句如下:
SELECT * FROM t_order WHERE ORDER_ID in (#{orderList})
SELECT * FROM t_order WHERE ORDER_ID in ('1,2,5')只能查到一条
将mapper.xml中的sql语句改为
SELECT * FROM t_order WHERE ORDER_ID in (${orderList})
SELECT * FROM t_order WHERE ORDER_ID in (1,2,5)就可以全部查到。

②对于表中的主键是varchar
SELECT * FROM t_order WHERE ORDER_ID in (#{orderList})
SELECT * FROM t_order WHERE ORDER_ID in ('1,2,5')查询不到
将mapper.xml中的sql语句改为
SELECT * FROM t_order WHERE ORDER_ID in (${orderList})
SELECT * FROM t_order WHERE ORDER_ID in ('1','2','5')就可以全部

'1,2,5'转为'1','2','5'步骤如下:

String categoryIdList = (String) formData.get("categoryIdList");
        if (!StringUtils.isEmpty(categoryIdList)) {
            String[] split = categoryIdList.split(",");
            String sqlParamter = "";
            for (String s : split) {
                sqlParamter += "'" + s + "',";
            }
            String substring = sqlParamter.substring(0, sqlParamter.length() - 1);
            formData.put("categoryIdList", substring);
        }

以上是关于Java--MyBatis批量插入批量更新和批量删除的主要内容,如果未能解决你的问题,请参考以下文章

Java--Mybatis批量更新

为啥批量插入/更新更快?批量更新如何工作?

jdbc-批量插入批量删除批量更新

mybatis+mysql批量插入和批量更新

mybatis批量插入和批量更新

Java批量插入更新操作