大家好,我是小白学编程。
目录
一、过程
最近在工作中遇到一个功能,使用 Mybatis 操作 MySql 批量更新时遇到一个报错,就是标题中的这个错误
***sql injection violation, multi-statement not allow****
我的 xml 是这样写的
<update id="updateStatusBatchById">
<foreach collection="updateList" item="item" index="index" separator=";" close="">
update tableName
set status = #{item.status},update_time = now(),update_login = #{item.updateLogin}
where vote_id = #{item.id}
</foreach>
</update>
当遇到这个错误的时候,我下意识的去看一下我的数据库连接串中有没有添加批量操作的配置,也就是 allowMultiQueries=true ,可是很失望,我加了,但是还是有这个错误,也就是说不是这个配置能解决的了的
我的数据库连接串是这样的
url: jdbc:mysql://127.0.0.1:3306/ymdb?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
于是百度,发现有很多关于这个问题的文章,当我看到这位大佬(在此要感谢各位大佬)的这篇文章后
SpringBoot+Mybatis+Druid批量更新multi-statement not allow异常
对我有了启发,既然是这样,我就可以那样。
二、原因
(以下是我解决完问题之后的个人理解记忆)
造成这个报错的原因是Druid 数据源中有代理过滤器(ProxyFilter),在这个过滤器中有一个防火墙过滤器(WallFilter),防火墙过滤器中有个防火墙配置(WallConfig),在这个防火墙配置中有一个配置项是 multiStatementAllow ,这个配置项的默认值是 false,就是因为它,导致的不允许一次性执行多条 Sql 语句导致的报错。
三、思路
既然直到了是这么回事,那我就看看这个配置什么时候初始化的,如果在我能观察到之前就初始化了,我是不是把它改一下就行;如果是在我观察之后才初始化的,是不是我自己设置一下就行了。
由于我的工程是 SpringBoot 的,通过配置类方式注入的数据源,在我 debug 的时候我发现,在我实例化 DruidDataSource 时 filters 中是没有数据的
那也就是说明,如果我在此处去设置 multiStatementAllow 值是可以的
四、解决办法
1、在数据库连接串中添加 allowMultiQueries=true 配置,如第二张图
2、SpringBoot工程在注入数据源时,设置 multiStatementAllow=true
@Bean(name = "mysqlDataSource")
@ConfigurationProperties(prefix = "spring.datasource.mysql")
@Primary
public DataSource writeDataSource() {
DataSource dataSource = DataSourceBuilder.create().type(dataSourceType).build();
if(dataSource instanceof DruidDataSource) {
DruidDataSource ds = (DruidDataSource)dataSource;
WallConfig wallConfig = new WallConfig();
wallConfig.setMultiStatementAllow(true);
WallFilter wallFilter = new WallFilter();
wallFilter.setConfig(wallConfig);
List<Filter> filters = Lists.newArrayList(wallFilter);
ds.setProxyFilters(filters);
return ds;
}
return dataSource;
}