shardingJdbc分表執行批次update不支援的解決方式

自学Java笔记本發表於2024-09-12

引言

本次場景,公司透過shardingjdbc 對mysql資料庫進行分表,模糊匹配 按照createTime,每季度一張表的方式,精確匹配按照creatTime的方式。關於模糊匹配、精確匹配,自行在shardingjdbc官網檢視,分表策略等。
由於是跟進createTime欄位去作為分表的key,那麼在執行 select、update、delete操作時,需要攜帶creatTime 欄位。

案例

在執行過程中,匯入的操作,基於easyexcel 我採用分批次的方式,批次去進行update操作,於是我的sql如下:

    <update id="batchUpdateTmsStatus">
        <foreach collection="tmsFollowBOList" item="item" separator=";">
            update bp_tms_logistics set expressStatus = #{item.expressStatus},userChange = 1,followStatus = #{item.status}
            where createTime = #{item.createTime,jdbcType=DATE}
            and expressNo = #{item.expressNo}
        </foreach>
    </update>

但是問題來了,透過日誌發現,執行的sql指令碼如下:

update xxxxx_2024_2
set expressStatus = ?,userChange = 1,followStatus = ?
where expressNo = ?
and  createTime = ?;
				 
update xxxxx
set expressStatus = ?,userChange = 1,followStatus = ?
where expressNo = ?
and  createTime = BETWEEN


::: [3, 2, SF2223211, 2024-09-10, 2, 1, SF05050505, 2024-09-09]

細心的可以發現,一個是xxxxx_2024_2 一個是xxxxx ,其實 xxxxx對於我們來說它只是虛擬表,並不存在,我們需要的是xxxxx_2024_2 的形式,而shardingjdbc 並沒有 透過代理的方式,代理到正確的資料庫表中,檢視官網issues 發現,並不支援批次update的方式,也就是我上面的語句。
issues:https://github.com/apache/shardingsphere/issues/6665

解決

由於並不支援批次的操作,剛開始的想法是想直接for迴圈連結資料庫得了,但是我覺得這樣並不符合自己的方式,於是,想了想,或許採用 case - when 的方式是否可以實現呢,於是我修改sql如下:


    <update id="batchUpdateTmsStatus">
        update xxxxx
        <trim prefix="set" suffixOverrides=",">
            <trim prefix="expressStatus=case" suffix="end,">
                <foreach collection="tmsFollowBOList" item="item" index="index">
                    <if test="item.expressStatus != null">
                        when expressNo = #{item.expressNo} AND createTime = #{item.createTime,jdbcType=DATE} THEN #{item.expressStatus}
                    </if>
                </foreach>
            </trim>
            <trim prefix="userChange=case" suffix="end,">
                <foreach collection="tmsFollowBOList" item="item" index="index">
                    <if test="item.expressStatus != null">
                        when expressNo = #{item.expressNo} AND createTime = #{item.createTime,jdbcType=DATE} THEN 1
                    </if>
                </foreach>
            </trim>
            <trim prefix="followStatus=case" suffix="end,">
                <foreach collection="tmsFollowBOList" item="item" index="index">
                    <if test="item.status != null">
                        when expressNo = #{item.expressNo} AND createTime = #{item.createTime,jdbcType=DATE} THEN #{item.status}
                    </if>
                </foreach>
            </trim>
        </trim>
    </update>

裡面的內容我就不解釋了,採用這個方式可以解決批次update 的方式,其中 when 中的條件需要符合哈。

相關文章