一、問題解決
項目里有個功能需要批量更新數據,本想直接在后台for循環里做更新操作,但想起之前看到的最好不要在循環中執行數據庫crud操作,因此就改用了直接在mybatis語句中使用foreach來執行批量更新操作(其實性能差不多,都是一條一條去更新),代碼如下:
<update id="updateListToNotDelete"> <foreach collection="userMenus" index="index" item="item" open="" separator=";" close=""> update t_sys_user_menu set is_delete = 0,version = version+1, object_name = #{item.objectName}, update_date = #{item.updateDate} where user_menu_uid = #{item.userMenuUid} </foreach> </update>
代碼沒問題吧,但當我執行的時候就有問題了,出現了下面這個錯誤
multi-statement not allow

一臉懵逼的我還以為是執行語句寫錯了,但檢查了好多遍也沒發現問題。網上找資料,發現原來是druid配置的問題,要想執行批量更新的操作,需要添加額外的配置。
首先在數據庫連接串后加上:
&allowMultiQueries=true
jdbc:mysql://192.168.1.129:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
然后還需要在DruidConfig中添加配置(這個類需要自己新建), 主要是需要添加wallFilter配置
/** * 使用阿里巴巴的Druid配置多數據源 * 需要在配置文件中指定,spring.datasource.type=com.alibaba.druid.pool.DruidDataSource * @author sxh * @date 2019年5月5日 * @Description * */ @Configuration public class DruidConfig { @Bean @ConfigurationProperties(prefix="spring.datasource") public DataSource druidPrimary(){ DruidDataSource druidDataSource = new DruidDataSource(); List<Filter> filterList = new ArrayList<>(); filterList.add(wallFilter()); druidDataSource.setProxyFilters(filterList); return new DruidDataSource(); } @Bean public WallFilter wallFilter(){ WallFilter wallFilter = new WallFilter(); wallFilter.setConfig(wallConfig()); return wallFilter; } @Bean public WallConfig wallConfig() { WallConfig config = new WallConfig(); config.setMultiStatementAllow(true);//允許一次執行多條語句 config.setNoneBaseStatementAllow(true);//允許一次執行多條語句 return config; } }
配置完成,再次執行代碼,成功解決!
二、另一種方法
在網上查閱博客的過程中,發現執行批量更新操作還有另外一種方法,就是使用Mybatis的xml去構建sql語句,然后交給數據庫執行,這種方法不需要對數據庫進行額外的配置,直接上代碼:
<update id="updateListToNotDelete"> update t_sys_user_menu <trim prefix="set" suffixOverrides=","> is_delete = 0,version = version+1, <trim prefix="object_name =(case" suffix="end),"> <foreach collection="userMenus" item="item"> <if test="item.objectName != null"> when user_menu_uid = #{item.userMenuUid} then #{item.objectName} </if> </foreach> </trim> <trim prefix="update_date =(case" suffix="end),"> <foreach collection="userMenus" item="item"> <if test="item.updateDate != null"> when user_menu_uid = #{item.userMenuUid} then #{item.updateDate} </if> </foreach> </trim> </trim> <where> user_menu_uid in <foreach collection="userMenus" item="item" index="index" open="(" separator="," close=")"> #{item.userMenuUid} </foreach> </where> </update>
sql最終執行的語句:
#使用SQL一次批量更新多條記錄 UPDATE t_sys_user_menu SET object_name = ( CASE WHEN user_menu_uid= 123 then 3 END ), update_date= ( CASE WHEN user_menu_uid= 1244 then '111' END ) WHERE user_menu_uid IN (123, 1244)