druid + presto报错:java.sql.SQLFeatureNotSupportedException: Batches not supported

1、场景描述

使用druid数据库连接池配合presto数据源进行查询时没有问题,数据可以正常查询和展示出来,但是在调用close方法进行关闭连接时报错,报错信息如下:

wyt01-test 2022-07-13 15:14:42,741 [http-nio-8080-exec-3] [ERROR] close statement error - [com.alibaba.druid.util.JdbcUtils.109] 
java.sql.SQLFeatureNotSupportedException: Batches not supported
	at io.prestosql.jdbc.PrestoStatement.clearBatch(PrestoStatement.java:394)
	at com.alibaba.druid.pool.DruidPooledConnection.closePoolableStatement(DruidPooledConnection.java:172)
	at com.alibaba.druid.pool.DruidPooledPreparedStatement.close(DruidPooledPreparedStatement.java:201)
	at com.alibaba.druid.util.JdbcUtils.close(JdbcUtils.java:98)
	at com.alibaba.druid.pool.DruidConnectionHolder.reset(DruidConnectionHolder.java:323)
	at com.alibaba.druid.pool.DruidDataSource.recycle(DruidDataSource.java:1949)
	at com.alibaba.druid.pool.DruidPooledConnection.recycle(DruidPooledConnection.java:351)
	at com.alibaba.druid.pool.DruidPooledConnection.close(DruidPooledConnection.java:288)
	at com.haiziwang.bigdata.mokeeper.web.util.PrestoJdbcPoolUtil.close(PrestoJdbcPoolUtil.java:87)
	at com.haiziwang.bigdata.mokeeper.web.service.impl.IModelListServiceImpl.notePreview(IModelListServiceImpl.java:1188)
	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 net.jplugin.core.ctx.impl.DefaultRuleInvocationHandler.invokeWithLog(DefaultRuleInvocationHandler.java:49)
	at net.jplugin.core.ctx.impl.DefaultRuleInvocationHandler.invokeWithTx(DefaultRuleInvocationHandler.java:113)
	at net.jplugin.core.ctx.impl.DefaultRuleInvocationHandler.lambda$static$2(DefaultRuleInvocationHandler.java:27)
	at net.jplugin.common.kits.filter.FilterChain.next(FilterChain.java:32)
	at net.jplugin.ext.gtrace.impl.RuleFilter4TraceLog.filter(RuleFilter4TraceLog.java:18)
	at net.jplugin.ext.gtrace.impl.RuleFilter4TraceLog.filter(RuleFilter4TraceLog.java:11)
	at net.jplugin.common.kits.filter.FilterChain.next(FilterChain.java:32)
	at net.jplugin.core.ctx.impl.filter4clazz.RuleCallFilterManagerRuleFilter.filter(RuleCallFilterManagerRuleFilter.java:97)
	at net.jplugin.core.ctx.impl.filter4clazz.RuleCallFilterManagerRuleFilter.filter(RuleCallFilterManagerRuleFilter.java:67)
	at net.jplugin.common.kits.filter.FilterChain.next(FilterChain.java:32)
	at net.jplugin.common.kits.filter.FilterManager.filter(FilterManager.java:42)
	at net.jplugin.core.ctx.impl.DefaultRuleInvocationHandler.invoke(DefaultRuleInvocationHandler.java:65)
	at net.jplugin.core.ctx.impl.RuleInterceptor.invoke(RuleInterceptor.java:134)
	at com.sun.proxy.$Proxy17.notePreview(Unknown Source)
	at com.haiziwang.bigdata.mokeeper.web.controller.ModelListController.notePreview(ModelListController.java:330)
	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 net.jplugin.core.ctx.impl.DefaultRuleInvocationHandler.invokeWithLog(DefaultRuleInvocationHandler.java:49)
	at net.jplugin.core.ctx.impl.DefaultRuleInvocationHandler.invokeWithTx(DefaultRuleInvocationHandler.java:113)
	at net.jplugin.core.ctx.impl.DefaultRuleInvocationHandler.lambda$static$2(DefaultRuleInvocationHandler.java:27)
	at net.jplugin.common.kits.filter.FilterChain.next(FilterChain.java:32)
	at net.jplugin.ext.gtrace.impl.RuleFilter4TraceLog.filter(RuleFilter4TraceLog.java:18)
	at net.jplugin.ext.gtrace.impl.RuleFilter4TraceLog.filter(RuleFilter4TraceLog.java:11)
	at net.jplugin.common.kits.filter.FilterChain.next(FilterChain.java:32)
	at com.haiziwang.platform.auth.BaseUserAuthInceptor.filterRuleMethod(BaseUserAuthInceptor.java:120)
	at net.jplugin.core.ctx.api.AbstractRuleMethodInterceptor.filter(AbstractRuleMethodInterceptor.java:25)
	at net.jplugin.core.ctx.impl.filter4clazz.RuleCallFilterManagerRuleFilter$ClassOwnedFilter.filter(RuleCallFilterManagerRuleFilter.java:199)
	at net.jplugin.core.ctx.impl.filter4clazz.RuleCallFilterManagerRuleFilter$ClassOwnedFilter.filter(RuleCallFilterManagerRuleFilter.java:186)
	at net.jplugin.common.kits.filter.FilterChain.next(FilterChain.java:32)
	at com.haiziwang.platform.auth.BaseSsoAuthInterceptor.filterRuleMethod(BaseSsoAuthInterceptor.java:127)
	at net.jplugin.core.ctx.api.AbstractRuleMethodInterceptor.filter(AbstractRuleMethodInterceptor.java:25)
	at net.jplugin.core.ctx.impl.filter4clazz.RuleCallFilterManagerRuleFilter$ClassOwnedFilter.filter(RuleCallFilterManagerRuleFilter.java:199)
	at net.jplugin.core.ctx.impl.filter4clazz.RuleCallFilterManagerRuleFilter$ClassOwnedFilter.filter(RuleCallFilterManagerRuleFilter.java:186)
	at net.jplugin.common.kits.filter.FilterChain.next(FilterChain.java:32)
	at com.haiziwang.platform.esf.server.interceptor.AppAuthInterceptor.filterRuleMethod(AppAuthInterceptor.java:38)
	at net.jplugin.core.ctx.api.AbstractRuleMethodInterceptor.filter(AbstractRuleMethodInterceptor.java:25)
	at net.jplugin.core.ctx.impl.filter4clazz.RuleCallFilterManagerRuleFilter$ClassOwnedFilter.filter(RuleCallFilterManagerRuleFilter.java:199)
	at net.jplugin.core.ctx.impl.filter4clazz.RuleCallFilterManagerRuleFilter$ClassOwnedFilter.filter(RuleCallFilterManagerRuleFilter.java:186)
	at net.jplugin.common.kits.filter.FilterChain.next(FilterChain.java:32)
	at com.haiziwang.platform.kflow.interceptor.FlowControlInterceptor.filterRuleMethod(FlowControlInterceptor.java:56)
	at net.jplugin.core.ctx.api.AbstractRuleMethodInterceptor.filter(AbstractRuleMethodInterceptor.java:25)
	at net.jplugin.core.ctx.impl.filter4clazz.RuleCallFilterManagerRuleFilter$ClassOwnedFilter.filter(RuleCallFilterManagerRuleFilter.java:199)
	at net.jplugin.core.ctx.impl.filter4clazz.RuleCallFilterManagerRuleFilter$ClassOwnedFilter.filter(RuleCallFilterManagerRuleFilter.java:186)
	at net.jplugin.common.kits.filter.FilterChain.next(FilterChain.java:32)
	at net.jplugin.common.kits.filter.FilterManager.filter(FilterManager.java:42)
	at net.jplugin.core.ctx.impl.filter4clazz.RuleCallFilterManagerRuleFilter.filter(RuleCallFilterManagerRuleFilter.java:99)
	at net.jplugin.core.ctx.impl.filter4clazz.RuleCallFilterManagerRuleFilter.filter(RuleCallFilterManagerRuleFilter.java:67)
	at net.jplugin.common.kits.filter.FilterChain.next(FilterChain.java:32)
	at net.jplugin.common.kits.filter.FilterManager.filter(FilterManager.java:42)
	at net.jplugin.core.ctx.impl.DefaultRuleInvocationHandler.invoke(DefaultRuleInvocationHandler.java:65)
	at net.jplugin.core.ctx.api.RuleProxyHelper.invokeWithRule(RuleProxyHelper.java:27)
	at net.jplugin.ext.webasic.impl.web.webex.WebExController$1.run(WebExController.java:87)
	at net.jplugin.ext.webasic.impl.filter.MethodFilterManager.executeWithFilter(MethodFilterManager.java:31)
	at net.jplugin.ext.webasic.impl.web.webex.WebExController.dohttp(WebExController.java:85)
	at net.jplugin.ext.webasic.impl.web.webex.WebExControllerSet.dohttp(WebExControllerSet.java:47)
	at net.jplugin.ext.webasic.impl.WebDriver.doHttpAcure(WebDriver.java:110)
	at net.jplugin.ext.webasic.impl.WebDriver.lambda$new$2(WebDriver.java:45)
	at net.jplugin.common.kits.filter.FilterChain.next(FilterChain.java:32)
	at net.jplugin.extension.reqrecoder.impl.ReqLogFilter.filter(ReqLogFilter.java:47)
	at net.jplugin.extension.reqrecoder.impl.ReqLogFilter.filter(ReqLogFilter.java:13)
	at net.jplugin.common.kits.filter.FilterChain.next(FilterChain.java:32)
	at net.jplugin.ext.gtrace.impl.HttpFilter4TraceLog.filter(HttpFilter4TraceLog.java:28)
	at net.jplugin.ext.gtrace.impl.HttpFilter4TraceLog.filter(HttpFilter4TraceLog.java:12)
	at net.jplugin.common.kits.filter.FilterChain.next(FilterChain.java:32)
	at net.jplugin.common.kits.filter.FilterManager.filter(FilterManager.java:42)
	at net.jplugin.ext.webasic.impl.WebDriver.dohttp(WebDriver.java:87)
	at net.jplugin.ext.webasic.impl.PluginServlet.dohttp(PluginServlet.java:64)
	at net.jplugin.ext.webasic.impl.PluginServlet.doPost(PluginServlet.java:53)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at com.thetransactioncompany.cors.CORSFilter.doFilter(CORSFilter.java:209)
	at com.thetransactioncompany.cors.CORSFilter.doFilter(CORSFilter.java:244)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:544)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:698)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:353)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:616)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:831)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1629)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)

2、问题追踪与分析

因为报错是在close方法中,于是查看close报错的方法栈,可以看到如下的流程信息:

druid + presto报错:java.sql.SQLFeatureNotSupportedException: Batches not supported_第1张图片

druid + presto报错:java.sql.SQLFeatureNotSupportedException: Batches not supported_第2张图片

即connection关闭时会调用数据源的recycle方法回收connection连接到连接池, 我们再深入看一下:

druid + presto报错:java.sql.SQLFeatureNotSupportedException: Batches not supported_第3张图片

可以看到再回收连接时会重设连接的一些信息,我们接着深入看一下:

druid + presto报错:java.sql.SQLFeatureNotSupportedException: Batches not supported_第4张图片 

可以看到重置connection连接时,会关闭所有的statement会话,因为我们用的是PrepareStatement,所以到DruidPooledPreparedStatement查看下关闭的具体方法:

druid + presto报错:java.sql.SQLFeatureNotSupportedException: Batches not supported_第5张图片

 druid + presto报错:java.sql.SQLFeatureNotSupportedException: Batches not supported_第6张图片

可以看到最druid关闭connection连接中的preparestatement时会调用presto jdbc驱动中的clearBatch方法,我们再到presto驱动中看一下该方法的实现:

druid + presto报错:java.sql.SQLFeatureNotSupportedException: Batches not supported_第7张图片

可以看到presto对该方法本身就不支持,而且也就是报错的根本原因。 

总结:druid线程池中连接关闭时,druid会同时关闭statement,而我们使用的prestatement,它在druid中会去调用jdbc驱动的clearBatch方法,这个方法在presto中并没有被实现,因此会报“Batches not supported”问题。

3、解决方式

1)重写druid中prestatement的关闭方法

2)重写presto驱动中的clearBatch方法。

3)替换prestatement为常规的statement(我使用的就是这种,比较前两种改动太大)

4、引申

使用druid连接时,只需要手动关闭connection连接即可,其内部会帮助我们关闭statement和resultset。因为在阅读connection关闭源码时,我们看到了如下一段代码:

for (Object item : statementTrace.toArray()) {
    Statement stmt = (Statement) item;
    JdbcUtils.close(stmt);
}

即在connection关闭的过程中,会将自己相关的statement也关闭掉,同理resultset也会再statement的关闭中被关闭,因此使用druid线程池关闭时只需要关闭connection即可。

你可能感兴趣的:(基础知识,java,sql,presto,druid)