MyBatis批量更新Mysql數據

之前寫的代碼,批量更新的操作都是使用for循環語句進行集合的遍歷,一次次調用單條更新的接口,代碼既不美觀,性能也不好,就想使用MyBatis在一個方法裏批量更新數據,我一共想到兩種思路,分享一下:

  1. 第一種就是使用MyBatis的 <foreach> 去循環創建多條完整的 update 語句,然後交由Mysql數據庫一條一條去執行(這個和之前的性能差不多,都是一條一條去更新)
  2. 第二種就是使用數據庫支持的case when函數,根據不同的條件去更新對應符合條件的數據

我們先來看看第一種方法吧:

1.使用 <foreach> 循環創建多條完整update語句

此處是將需要修改的參數放入一個 List 中,然後遍歷list集合,創建多條 update 語句,最終的結果如下:

1.1 MyBatis 的XML語句

<!--批量更新 -->
	<update id="updateListByHouseId" parameterType="java.util.ArrayList">
		<foreach close=";" collection="list" index="index" item="item" open="" separator=";">
			update rba_house_status
			<trim prefix="set" suffixOverrides=",">
				last_push_time = now(),
				<if test="item.pushStatus != null">push_status = #{item.pushStatus},</if>
				<if test="item.createStatus != null">create_status = #{item.createStatus},</if>
				<if test="item.houseCreateTime != null">house_create_time = #{item.houseCreateTime},</if>
				<if test="item.updateStatus != null">update_status = #{item.updateStatus},</if>
				update_time = now(),
				<if test="item.auditStatus != null">audit_status = #{item.auditStatus},</if>
				<if test="item.auditDesc != null">audit_desc = #{item.auditDesc},</if>
				<if test="item.hotelId != null">hotel_id = #{item.hotelId},</if>
			</trim>
			<where>house_id = #{item.houseId}</where>
		</foreach>
	</update>

1.2 MyBatis最終生成的SQL

update rba_house_status set last_push_time = now(), push_status = ?, create_status = ?, house_create_time = ?, update_status = ?, update_time = now(), audit_status = ?, audit_desc = ?, hotel_id = ? WHERE house_id = ? ; 
update rba_house_status set last_push_time = now(), push_status = ?, create_status = ?, house_create_time = ?, update_status = ?, update_time = now(), audit_status = ?, audit_desc = ?, hotel_id = ? WHERE house_id = ? ; 

上腳本中的 “?” 對應參數對象中各個對應字段的值
寫到這裏,本以爲第一種方法就可以執行了,直接去進行測試了,就在這時,服務器跟我鬧彆扭,扭扭捏捏不執行,一直報一個錯誤: multi-statement not allow
一臉懵逼一臉懵逼 icon爲啥還不讓執行了?
查了半天資料發現,原來MyBatis想要一次執行多條語句是需要進行額外的配置,配置在數據庫鏈接串裏面,就是在鏈接串最後面加一個: &allowMultiQueries=true ,如下所示:

jdbc:mysql://127.0.0.1:3306/test_db?characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&allowMultiQueries=true

加完以後信誓旦旦開始了第二次測試執行,按理來說應該到這裏就可以,結果執行還是報錯,難道是我執行的姿勢不對?清除之前編譯的文件,再試,還是不行在這裏插入圖片描述好吧,繼續google and 百度…
最後歷經千辛萬苦,還是沒結果,看來還是隻能自己找答案了,最後偶然間發現在數據源的配置文件裏有一個 com.alibaba.druid.wall.WallFilter 的配置,這個filter裏面有個一配置項 com.alibaba.druid.wall.WallConfig ,這個配置項裏面有個一 multiStatementAllow ,這個配置默認是false,果斷改掉配置,添加一個 multiStatementAllow 的配置,如下:

<bean id="wall-filter-config" class="com.alibaba.druid.wall.WallConfig" init-method="init">
   	 	<property name="dir" value="META-INF/druid/wall/mysql" />
        <property name="selectWhereAlwayTrueCheck" value="false" />
        <property name="selectHavingAlwayTrueCheck" value="false" />
        <property name="multiStatementAllow" value="true" />
    </bean>

配置完成,再次執行測試代碼!
在這裏插入圖片描述

下面說一下第二種方式,使用mysql自己的函數執行:

2.使用數據庫支持的case when函數

這種方式比較簡單,就是使用 MyBatisXML 去構建數據庫SQL,然後交由數據庫執行。原理比較簡單,直接上代碼給大家看一下:

2.1 需要構建的數據庫語句
#使用SQL一次批量更新多條記錄
UPDATE rba_house_status 
SET 
audit_status = (
CASE 
WHEN house_id = 100023 then 3 
END
),
audit_desc = (
CASE 
WHEN house_id = 100010 then '111' 
END
),
last_push_time = now()
WHERE house_id IN (100023,100010)

2.2 MyBatis 的xml

<!--批量多字段更新-->
	<update id="updateListByHouseId" parameterType="java.util.ArrayList">
			update rba_house_status
			<trim prefix="set" suffixOverrides=",">
				<trim prefix="push_status =(case" suffix="end),">
					<foreach collection="list" item="item">
						<if test="item.pushStatus != null">
							when house_id = #{item.houseId} then #{item.pushStatus}
						</if>
					</foreach>
				</trim>

				<trim prefix="create_status =(case" suffix="end),">
					<foreach collection="list" item="item">
						<if test="item.createStatus != null">
							when house_id = #{item.houseId} then #{item.createStatus}
						</if>
					</foreach>
				</trim>

				<trim prefix="house_create_time =(case" suffix="end),">
					<foreach collection="list" item="item">
						<if test="item.houseCreateTime != null">
							when house_id = #{item.houseId} then #{item.houseCreateTime}
						</if>
					</foreach>
				</trim>

				update_time = now(),
		</trim>
		<where>
			house_id in
			<foreach collection="list" item="item" index="index" open="(" separator="," close=")">
				#{item.houseId}
			</foreach>
		</where>
	</update>

至此,兩種方式就介紹完畢,大家還有什麼其他方法,歡迎交流!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章