栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

使用case when then语句解决mybatis批量更新multi-statement not allow问题

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用case when then语句解决mybatis批量更新multi-statement not allow问题

近期在开发过程中遇到了MyBatis批量更新的问题,控制台报错 multi-statement not allow,对应xml文件中的SQL如下:

  
        
            UPDATE sjgx_fwml_sqxx
            
                
                    zdqqcs= #{fwsq.zdqqcs},
                
                
                    ljqqcs= #{fwsq.ljqqcs},
                
                gxsj=NOW()
            
            WHERe id=#{fwsq.id}
        
    

执行后报错:
 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 filterList = null;
        DruidDataSource druidDataSource = new DruidDataSource();
        List 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 sjgx_fwml_sqxx
        

            
                
                    
                        WHEN id=#{i.id} THEN #{i.zdqqcs}
                    
                
            

            
                
                    
                        WHEN id=#{i.id} THEN #{i.ljqqcs}
                    
                
            

            
                
                    
                        WHEN id=#{i.id} THEN #{i.gxsj}
                    
                
            

        
        WHERe id IN
        
            #{i.id}
        
    

控制台打印执行的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的问题,只是绕开了这个问题,使用了另一种方式来解决,
特此记录,希望遇到或已解决此问题的同学予以指教,互相学习,互相探讨!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/458556.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号