关于如何开启multiStatementAllow,一次执行多条sql,这里结合项目,来说明一下。
首先搞清楚,multiStatementAllow配置在哪,其实就是阿里Druid框架中WallConfig.class中的一个属性。源码如下:
package com.alibaba.druid.wall;
import com.alibaba.druid.util.Utils;
import com.alibaba.druid.wall.spi.WallVisitorUtils;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
public class WallConfig implements WallConfigMBean {
private boolean noneBaseStatementAllow = false;
private boolean callAllow = true;
private boolean selelctAllow = true;
private boolean selectIntoAllow = true;
private boolean selectIntoOutfileAllow = false;
private boolean selectWhereAlwayTrueCheck = true;
private boolean selectHavingAlwayTrueCheck = true;
private boolean selectUnionCheck = true;
private boolean selectMinusCheck = true;
private boolean selectExceptCheck = true;
private boolean selectIntersectCheck = true;
private boolean createTableAllow = true;
private boolean dropTableAllow = true;
private boolean alterTableAllow = true;
private boolean renameTableAllow = true;
private boolean hintAllow = true;
private boolean lockTableAllow = true;
private boolean startTransactionAllow = true;
private boolean conditionAndAlwayTrueAllow = false;
private boolean conditionAndAlwayFalseAllow = false;
private boolean conditionDoubleConstAllow = false;
private boolean conditionLikeTrueAllow = true;
private boolean selectAllColumnAllow = true;
private boolean deleteAllow = true;
private boolean deleteWhereAlwayTrueCheck = true;
private boolean deleteWhereNoneCheck = false;
private boolean updateAllow = true;
private boolean updateWhereAlayTrueCheck = true;
private boolean updateWhereNoneCheck = false;
private boolean insertAllow = true;
private boolean mergeAllow = true;
private boolean minusAllow = true;
private boolean intersectAllow = true;
private boolean replaceAllow = true;
private boolean setAllow = true;
private boolean commitAllow = true;
private boolean rollbackAllow = true;
private boolean useAllow = true;
private boolean multiStatementAllow = false;
private boolean truncateAllow = true;
private boolean commentAllow = false;
private boolean strictSyntaxCheck = true;
private boolean constArithmeticAllow = true;
private boolean limitZeroAllow = false;
private boolean describeAllow = true;
private boolean showAllow = true;
private boolean schemaCheck = true;
private boolean tableCheck = true;
private boolean functionCheck = true;
private boolean objectCheck = true;
private boolean variantCheck = true;
private boolean mustParameterized = false;
private boolean doPrivilegedAllow = false;
protected final Set<String> denyFunctions = new ConcurrentSkipListSet();
protected final Set<String> denyTables = new ConcurrentSkipListSet();
protected final Set<String> denySchemas = new ConcurrentSkipListSet();
protected final Set<String> denyVariants = new ConcurrentSkipListSet();
protected final Set<String> denyObjects = new ConcurrentSkipListSet();
protected final Set<String> permitFunctions = new ConcurrentSkipListSet();
protected final Set<String> permitTables = new ConcurrentSkipListSet();
protected final Set<String> permitSchemas = new ConcurrentSkipListSet();
protected final Set<String> permitVariants = new ConcurrentSkipListSet();
protected final Set<String> readOnlyTables = new ConcurrentSkipListSet();
private String dir;
private boolean inited;
private String tenantTablePattern;
private String tenantColumn;
private WallConfig.TenantCallBack tenantCallBack;
private boolean wrapAllow = true;
private boolean metadataAllow = true;
private boolean conditionOpXorAllow = false;
private boolean conditionOpBitwseAllow = true;
private boolean caseConditionConstAllow = false;
private boolean completeInsertValuesCheck = false;
private int insertValuesCheckSize = 3;
... 省略
}
multiStatementAllow默认值为false,也就是说默认不开启一次执行多条sql语句的。
如何支持呢?本质就是把multiStatementAllow的值置为false,但是考虑到不同项目,数据源的配置是不同的,所以具体的实现
方案也是不同的。但是核心思想是不变的,我们需要拦截数据源,然后把我们的修改注入到Datasource。
@Bean(name = "wallFilter")
@DependsOn("wallConfig")
public WallFilter wallFilter(WallConfig wallConfig) {
WallFilter wallFilter = new WallFilter();
wallFilter.setConfig(wallConfig);
return wallFilter;
}
@Bean(name = "wallConfig")
public WallConfig wallConfig() {
WallConfig wallConfig = new WallConfig();
wallConfig.setMultiStatementAllow(Boolean.TRUE);
return wallConfig;
}
如何把这个filter注入到datasource呢,如果我们可以直接获取到datasource的话,那么,直接按照网上的方式,就可以了。如下
List<Filter> filters = new ArrayList<>();
filters.add(wallFilter);
datasource.setProxyFilters(filters);
但是有些项目,数据源是进行了统一的管理的,也就是我们不能直接获取到datasource,只能通过配置来注入这个filter,
怎么办呢?思路是:找到filter配置,然后把我们自定义的filter这个bean:wallFilter配置上去即可。
xx:
xxxx:
server:
enablecache: true
datasource:
driver : com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/databasename?serverTimezone=GMT%2b8&useSSL=false&Unicode=true&characterEncoding=utf8&autoReconnectForPools=true&allowMultiQueries=true
user: root
password: 123456789
mapperLocations: classpath:mybatis/*.xml
timeBetweenEvictionRunsMillis: 60000
filters: wallFilter
这样配置以后,我们就可以执行下面这种多条sql了。
<update id="batchUpdateTest">
<foreach collection="pojos" item="pojo" index="index" open="" close="" separator=";">
UPDATE table_name
SET `name` = #{pojo.name},
`update_time` = #{pojo.updateTime}
WHERE `id` = #{pojo.id} and `code` = #{pojo.code}
</foreach>
</update>
本地测试是OK的,但是后面部署到测试环境,发现有问题,报错如下:
2020-07-27 16:23:31,565 [http-nio-10015-exec-7] ERROR xx.xxxxxx.xxx.xxxxx.xxx.controller.XxxxController - [ANONYMOUS - 6b636ad5b9e949ff - 6b636ad5b9e949ff] - error
org.springframework.transaction.TransactionSystemException: Could not commit JDBC transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Communications link failure during commit(). Transaction resolution unknown.
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doCommit(DataSourceTransactionManager.java:275)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:485)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
at xx.xxxxxx.xxx.xxxxx.xxx.service.impl.OmsSapActualInventoryServiceImpl$$EnhancerBySpringCGLIB$$6e9713d5.batchUpdateBySkuAndWarehouse(<generated>)
at xx.xxxxxx.xxx.xxxxx.xxx.service.impl.OmsInventoryBatchUpdateService.updateInventoryThenNoticeInv(OmsInventoryBatchUpdateService.java:204)
at xx.xxxxxx.xxx.xxxxx.xxx.controller.OmsInventoryController.batchUpdateReserveInventory(OmsInventoryController.java:180)
at xx.xxxxxx.xxx.xxxxx.xxx.controller.OmsInventoryController$$FastClassBySpringCGLIB$$d31d8de7.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at com.alibaba.druid.support.spring.stat.DruidStatInterceptor.invoke(DruidStatInterceptor.java:72)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
at xx.xxxxxx.xxx.xxxxx.xxx.controller.OmsInventoryController$$EnhancerBySpringCGLIB$$1305761d.batchUpdateReserveInventory(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:832)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:743)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:961)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:895)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:869)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.java:281)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:115)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.cloud.sleuth.instrument.web.TraceFilter.doFilterInternal(TraceFilter.java:122)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:103)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:528)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1099)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:670)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Communications link failure during commit(). Transaction resolution unknown.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
at com.mysql.jdbc.Util.getInstance(Util.java:387)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:917)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:896)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:885)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860)
at com.mysql.jdbc.ConnectionImpl.commit(ConnectionImpl.java:1618)
at com.alibaba.druid.pool.DruidPooledConnection.commit(DruidPooledConnection.java:731)
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doCommit(DataSourceTransactionManager.java:272)
... 94 common frames omitted
首先这是一个新的报错了,这个报错的原因网上搜了一下。