近期在开发过程中遇到了MyBatis批量更新的问题,控制台报错?multi-statement not allow,对应xml文件中的SQL如下:
? <update id="batchUpdateFwzymlAndQqfxx" parameterType="vo.pojo.PageData">
? ? ? ? <foreach collection="fwsqupdatelist" item="fwsq" separator=",">
? ? ? ? ? ? UPDATE sjgx_fwml_sqxx
? ? ? ? ? ? <set>
? ? ? ? ? ? ? ? <if test="fwsq.zdqqcs!=null and fwsq.zdqqcs!=''" >
? ? ? ? ? ? ? ? ? ? zdqqcs= #{fwsq.zdqqcs},
? ? ? ? ? ? ? ? </if>
? ? ? ? ? ? ? ? <if test="fwsq.ljqqcs!=null and fwsq.ljqqcs!=''" >
? ? ? ? ? ? ? ? ? ? ljqqcs= #{fwsq.ljqqcs},
? ? ? ? ? ? ? ? </if>
? ? ? ? ? ? ? ? gxsj=NOW()
? ? ? ? ? ? </set>
? ? ? ? ? ? WHERE id=#{fwsq.id}
? ? ? ? </foreach>
? ? </update>
执行后报错: ?org.springframework.jdbc.UncategorizedSQLException:? ### Error updating database. ?Cause: java.sql.SQLException: sql injection violation, multi-statement not allow :? ?? ??? ?UPDATE sjgx_fwml_sqxx? ?? ??? ?SET zdqqcs = ?, ?? ??? ?ljqqcs = ?, ?? ??? ?gxsj = NOW( )? ?? ??? ?WHERE ?? ??? ??? ?id =?; ?? ??? ??? ? ?? ??? ?UPDATE sjgx_fwml_sqxx? ?? ??? ?SET zdqqcs = ?, ?? ??? ?ljqqcs = ?, ?? ??? ?gxsj = NOW( )? ?? ??? ?WHERE ?? ??? ??? ?id =?; ?? ??? ??? ? ?? ??? ?UPDATE sjgx_fwml_sqxx? ?? ??? ?SET zdqqcs = ?, ?? ??? ?ljqqcs = ?, ?? ??? ?gxsj = NOW( )? ?? ??? ?WHERE ?? ??? ??? ?id =?; ?? ??? ??? ? ?? ??? ?UPDATE sjgx_fwml_sqxx? ?? ??? ?SET zdqqcs = ?, ?? ??? ?ljqqcs = ?, ?? ??? ?gxsj = NOW( )? ?? ??? ?WHERE ?? ??? ??? ?id =?; ?? ??? ??? ? ?? ??? ?UPDATE sjgx_fwml_sqxx? ?? ??? ?SET zdqqcs = ?, ?? ??? ?ljqqcs = ?, ?? ??? ?gxsj = NOW( )? ?? ??? ?WHERE ?? ??? ??? ?id =?; ?? ??? ??? ? ?? ??? ?UPDATE sjgx_fwml_sqxx? ?? ??? ?SET zdqqcs = ?, ?? ??? ?ljqqcs = ?, ?? ??? ?gxsj = NOW( )? ?? ??? ?WHERE ?? ??? ??? ?id =?
由控制台可见,其mybatis默认不支持多条语句的更新,需要设置相关属性。从社区里看到的解决方案大致思路为,先检查本地配置文件的url中是否配置了allowMultiQueries=true,如果配置了,但还是不起作用,再写一个配置类来解决。 查看本地的application.yml文件中的 ? ? ?url: jdbc:mysql://127.0.0.1:3306/sk_sjz_sjgx_dev?allowMultiQueries=true&useUnicode=true&characterEncoding=utf-8&autoReconnect=true 已经加上了allowMultiQueries=true
再写一个配置类MyBatisConfig:
@Configuration
public class MyBatisConfig {
? ? @Bean
? ? @ConfigurationProperties(prefix = "spring.datasource")
? ? public DataSource dataSource(){
? ? ? ? List<Filter> filterList = null;
? ? ? ? DruidDataSource druidDataSource = new DruidDataSource();
? ? ? ? List<Filter> proxyFilters = druidDataSource.getProxyFilters();
? ? ? ? boolean isExit = false;
? ? ? ? for(Filter filter:proxyFilters){
? ? ? ? ? ? if(filter instanceof ?WallFilter){
? ? ? ? ? ? ? ? ((WallFilter) filter).setConfig(wallConfig());
? ? ? ? ? ? ? ? isExit = true;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if(!isExit){
? ? ? ? ? ? filterList= new ArrayList<>();
? ? ? ? ? ? filterList.add(wallFilter());
? ? ? ? ? ? druidDataSource.setProxyFilters(filterList);
? ? ? ? }
? ? ? ? return druidDataSource;
? ? }
? ? @Bean
? ? public WallFilter wallFilter(){
? ? ? ? WallFilter wallFilter = new WallFilter();
? ? ? ? wallFilter.setDbType(DbType.MYSQL.getDb());
? ? ? ? wallFilter.setConfig(wallConfig());
? ? ? ? return wallFilter;
? ? }
? ? @Bean
? ? public WallConfig wallConfig(){
? ? ? ? WallConfig config = new WallConfig();
? ? ? ? config.setMultiStatementAllow(true);//允许一次执行多条语句
? ? ? ? config.setNoneBaseStatementAllow(true); //允许非基本语句的其他语句
? ? ? ? return config;
? ? }
}
但还是不起作用,死活不好使,还报出了其他的错误:
Failed to obtain JDBC Connection: dbType not support : null,url null.........
这个若要讲清楚,必须了解MyBatis和DruidDataSource的底层实现,暂时还没有挖掘那么深, 就尝试了另一种批量更新的方式,即绕开了multi-statement not allow的问题,如下所示,
使用?case when?then 语句,可批量更新的操作:
<update id="batchUpdateFwzymlAndQqfxx" parameterType="vo.pojo.PageData">
? ? ? ? UPDATE sjgx_fwml_sqxx
? ? ? ? <trim prefix="set" suffixOverrides=",">
? ? ? ? ? ? <trim prefix="zdqqcs =case" suffix="end,">
? ? ? ? ? ? ? ? <foreach collection="updatelist" item="i" index="index">
? ? ? ? ? ? ? ? ? ? <if test="i.zdqqcs!=null">
? ? ? ? ? ? ? ? ? ? ? ? WHEN id=#{i.id} THEN #{i.zdqqcs}
? ? ? ? ? ? ? ? ? ? </if>
? ? ? ? ? ? ? ? </foreach>
? ? ? ? ? ? </trim>
? ? ? ? ? ? <trim prefix="ljqqcs =case" suffix="end,">
? ? ? ? ? ? ? ? <foreach collection="updatelist" item="i" index="index">
? ? ? ? ? ? ? ? ? ? <if test="i.ljqqcs!=null">
? ? ? ? ? ? ? ? ? ? ? ? WHEN id=#{i.id} THEN #{i.ljqqcs}
? ? ? ? ? ? ? ? ? ? </if>
? ? ? ? ? ? ? ? </foreach>
? ? ? ? ? ? </trim>
? ? ? ? ? ? <trim prefix="gxsj =case" suffix="end,">
? ? ? ? ? ? ? ? <foreach collection="updatelist" item="i" index="index">
? ? ? ? ? ? ? ? ? ? <if test="i.gxsj!=null">
? ? ? ? ? ? ? ? ? ? ? ? WHEN id=#{i.id} THEN #{i.gxsj}
? ? ? ? ? ? ? ? ? ? </if>
? ? ? ? ? ? ? ? </foreach>
? ? ? ? ? ? </trim>
? ? ? ? </trim>
? ? ? ? WHERE id IN
? ? ? ? <foreach collection="updatelist" item="i" open="(" close=")" separator=",">
? ? ? ? ? ? #{i.id}
? ? ? ? </foreach>
? ? </update>
控制台打印执行的sql为: UPDATE sjgx_fwml_sqxx? SET zdqqcs = CASE ?? ? ?? ?WHEN id =? THEN ?? ??? ?? ?WHEN id =? THEN ?? ??? ?? ?WHEN id =? THEN ?? ??? ?? ?WHEN id =? THEN ?? ??? ?? ?WHEN id =? THEN ?? ??? ?? ?WHEN id =? THEN ?? ??? ?? ?END, ?? ?ljqqcs = CASE ?? ??? ? ?? ??? ?WHEN id =? THEN ?? ??? ??? ?? ??? ?WHEN id =? THEN ?? ??? ??? ?? ??? ?WHEN id =? THEN ?? ??? ??? ?? ??? ?WHEN id =? THEN ?? ??? ??? ?? ??? ?WHEN id =? THEN ?? ??? ??? ?? ??? ?WHEN id =? THEN ?? ??? ??? ?? ?END, ?? ?gxsj = CASE ?? ??? ? ?? ??? ?WHEN id =? THEN ?? ??? ??? ?? ??? ?WHEN id =? THEN ?? ??? ??? ?? ??? ?WHEN id =? THEN ?? ??? ??? ?? ??? ?WHEN id =? THEN ?? ??? ??? ?? ??? ?WHEN id =? THEN ?? ??? ??? ?? ??? ?WHEN id =? THEN ?? ??? ??? ?? ?END? WHERE id IN ( ?, ?, ?, ?, ?, ? )
其他博客中也将末尾处的where条件使用OR来匹配,如: ?WHERE ? ? ? ?id=? ? ? ?OR id=? ?? ? OR id=? ?? ? OR id=? ?? ? OR id=? ?? ? OR id=?
也是没有问题的,但是实际开发中不建议使用OR。 经测试,如果IN和OR所在列有索引或主键,OR和IN没有差别,随着数据量的增加,执行计划和执行时间几乎一样 如果IN和OR所在列没有索引和主键,随着数据量的增加,IN的性能不受影响,而OR的性能会下降的非常厉害。 ? ? 以上方式实际并未解决multi-statement not allow的问题,只是绕开了这个问题,使用了另一种方式来解决, 特此记录,希望遇到或已解决此问题的同学予以指教,互相学习,互相探讨!
|