spring cloud+mybatis+阿里Druid:如何开启配置multiStatementAllow支持一次执行多条sql

 

关于如何开启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

 

首先这是一个新的报错了,这个报错的原因网上搜了一下。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
下面是一个简单的交易的示例,使用Spring CloudMyBatis框架: 1. 创建数据库表 ``` CREATE TABLE `transaction` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `amount` decimal(10,2) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ``` 2. 创建实体类 ``` public class Transaction { private int id; private int userId; private BigDecimal amount; // 省略getter和setter方法 } ``` 3. 创建Mapper接口 ``` @Mapper public interface TransactionMapper { @Insert("INSERT INTO transaction(user_id, amount) VALUES(#{userId}, #{amount})") int insert(Transaction transaction); } ``` 4. 创建Service类 ``` @Service public class TransactionService { @Autowired private TransactionMapper transactionMapper; public void insert(Transaction transaction) { transactionMapper.insert(transaction); } } ``` 5. 创建Controller类 ``` @RestController public class TransactionController { @Autowired private TransactionService transactionService; @PostMapping("/transaction") public void createTransaction(@RequestBody Transaction transaction) { transactionService.insert(transaction); } } ``` 6. 配置Spring Cloud 在application.yml中添加以下配置: ``` spring: datasource: url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false username: root password: 123456 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.demo.entity ``` 7. 启动应用程序 运行主类,即可启动应用程序。然后,您可以使用Postman或其他HTTP客户端发送POST请求来创建交易: ``` POST http://localhost:8080/transaction { "userId": 1, "amount": 100.00 } ``` 以上就是一个简单的交易的示例,您可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值