一、该问题的重现步骤是什么?
1、下载一份新的 bladex-boot 的代码,版本为 2.9.1
2、在工程 pom.xml 文件中加入 TDengine 驱动的依赖,版本为 2.0.38,如下:
com.taosdata.jdbc taos-jdbcdriver 2.0.38
3、修改 org.springblade.common.launch.Launcher 类中的配置,启用多数据源:
@AutoService(LauncherService.class) public class LauncherServiceImpl implements LauncherService { @Override public void launcher(SpringApplicationBuilder builder, String appName, String profile, boolean isLocalDev) { Properties props = System.getProperties(); PropsUtil.setProperty(props, "spring.cloud.sentinel.transport.dashboard", LauncherConstant.sentinelAddr(profile)); PropsUtil.setProperty(props, "spring.datasource.dynamic.enabled", "true"); // <-- 这里改为 true // 开启elk日志 //PropsUtil.setProperty(props, "blade.log.elk.destination", LauncherConstant.elkAddr(profile)); } }
4、 修改配置文件,改成多数据源的配置:
application.yml:
spring: datasource: dynamic: primary: mysql datasource: mysql: driver-class-name: com.mysql.cj.jdbc.Driver druid: validation-query: select 1 validation-query-timeout: 2000 initial-size: 5 max-active: 20 min-idle: 5 max-wait: 60000 test-on-borrow: false test-on-return: false test-while-idle: true time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 stat-view-servlet: enabled: true login-username: blade login-password: 1qaz@WSX web-stat-filter: enabled: true url-pattern: /* exclusions: '*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*' session-stat-enable: true session-stat-max-count: 10 tdengine: driver-class-name: com.taosdata.jdbc.TSDBDriver druid: validation-query: select 1 validation-query-timeout: 2000 initial-size: 5 max-active: 20 min-idle: 5 max-wait: 60000 test-on-borrow: false test-on-return: false test-while-idle: true time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 stat-view-servlet: enabled: true login-username: blade login-password: 1qaz@WSX web-stat-filter: enabled: true url-pattern: /* exclusions: '*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*' session-stat-enable: true session-stat-max-count: 10
application-dev.yml:
#数据源配置 spring: datasource: dynamic: datasource: mysql: url: jdbc:mysql://localhost:3306/bladex_boot?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true username: root password: root1234 tdengine: url: jdbc:TAOS://localhost:6030/ems?user=root&password=taosdata username: root password: taosdata
其中配置文件如何配置,参考:
dynamic-datasource-spring-boot-starter 的文档:https://baomidou.com/pages/a61e1b/
druid 文档关于多数据源配置的说明:https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter#如何配置多数据源
5、编写两个测试接口,一个测试创建 MySQL 的表,另一个测试创建 TDengine 的表。代码如下图,是一个简单的三层结构的代码:
其中,关键的代码如下:
StudentMapper.xml:
drop table if exists biz_student; CREATE TABLE `biz_student` ( `id` bigint NOT NULL COMMENT '主键', `name` varchar(20) COMMENT '用户名', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户表';
MeterMapper.xml:
drop stable if exists meter; CREATE stable meter ( ts timestamp, a int, b int ) TAGS ( x int, y int );
TestController.java:
@RestController @RequestMapping("/test") public class TestController extends BladeController { @Autowired private StudentService studentService; @Autowired private MeterService meterService; @GetMapping("/mysql") public String testMysql() { studentService.dropTable(); studentService.createTable(); return "success"; } @GetMapping("/tdengine") public String testTDengine() { meterService.dropSuperTable(); meterService.createSuperTable(); return "success"; } }
6、测试两个接口。
测试 MySQL 的建表的接口,成功:
测试 TDengine 的建表的接口,报错:
完整日志、报错信息请看最后的附件。
7、 已经排除了 sql 语法错误的嫌疑,TDengine 的建表语句放到 TDengine 去运行,是没问题的:
8、我还自己新建一个 spring-boot 工程,使用完全相同版本的 Spring Boot、Druid、TDengine、dynamic-datasource-spring-boot-starter、Mybatis Plus 等配置起一个多数据源的项目,把相同的测试代码放上去跑,是没有报错的。
完整的代码请看最后附件。
二、你期待的结果是什么?实际看到的又是什么?
希望使用 bladex-boot 实现多数据源,能够连接 MySQL 和 TDengine 两种数据库,并可以执行 TDengine 的建表语句。
因为我们是做物联网方面的系统的,其中一个业务场景就是,当用户新建一个产品的时候,需要对应在 TDengine 建一个超级表。
备注:
TDengine 是个国产的时序数据库。TDengne 安装方式可以参考这里:https://docs.taosdata.com/get-started/
三、你正在使用的是什么产品,什么版本?在什么操作系统上?
操作系统:Deepin V20
bladex-boot:2.9.1
TDengine:2.6.1
TDengine Java 驱动:2.0.38
MySQL Java 驱动:8.0.22
Druid:1.2.8
dynamic-datasource-spring-boot-starter:3.3.6
四、请提供详细的错误堆栈信息,这很重要。
2022-05-31 22:19:14.870 WARN 13884 --- [ XNIO-1 task-1] com.alibaba.druid.sql.SQLUtils : rowFormat error com.alibaba.druid.sql.parser.ParserException: TODO pos 11, line 1, column 6, token IDENTIFIER stable at com.alibaba.druid.sql.parser.SQLStatementParser.parseDrop(SQLStatementParser.java:836) at com.alibaba.druid.sql.parser.SQLStatementParser.parseStatementList(SQLStatementParser.java:397) at com.alibaba.druid.sql.parser.SQLStatementParser.parseStatementList(SQLStatementParser.java:114) at com.alibaba.druid.sql.SQLUtils.format(SQLUtils.java:346) at com.alibaba.druid.sql.SQLUtils.format(SQLUtils.java:339) at org.springblade.core.mp.plugins.SqlLogInterceptor.statement_close(SqlLogInterceptor.java:128) at com.alibaba.druid.filter.FilterChainImpl.statement_close(FilterChainImpl.java:2904) at com.alibaba.druid.filter.stat.StatFilter.statement_close(StatFilter.java:350) at com.alibaba.druid.filter.FilterChainImpl.statement_close(FilterChainImpl.java:2904) at com.alibaba.druid.proxy.jdbc.StatementProxyImpl.close(StatementProxyImpl.java:134) at com.alibaba.druid.pool.DruidPooledStatement.close(DruidPooledStatement.java:516) at com.alibaba.druid.pool.DruidPooledPreparedStatement.closeInternal(DruidPooledPreparedStatement.java:209) at com.alibaba.druid.pool.DruidPooledConnection.closePoolableStatement(DruidPooledConnection.java:205) at com.alibaba.druid.pool.DruidPooledPreparedStatement.close(DruidPooledPreparedStatement.java:201) at org.apache.ibatis.executor.BaseExecutor.closeStatement(BaseExecutor.java:283) at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:52) at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117) 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.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49) at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:106) at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) at com.sun.proxy.$Proxy266.update(Unknown Source) at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:194) 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.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) at com.sun.proxy.$Proxy138.update(Unknown Source) at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:288) at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:64) at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) at com.sun.proxy.$Proxy199.dropSuperTable(Unknown Source) at org.springblade.modules.demo.service.impl.MeterServiceImpl.dropSuperTable(MeterServiceImpl.java:39) at org.springblade.modules.demo.service.impl.MeterServiceImpl$$FastClassBySpringCGLIB$$17f755ca.invoke() at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) at com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationInterceptor.invoke(DynamicDataSourceAnnotationInterceptor.java:50) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692) at org.springblade.modules.demo.service.impl.MeterServiceImpl$$EnhancerBySpringCGLIB$$1dd9a4cd.dropSuperTable( ) at org.springblade.modules.demo.controller.TestController.testTDengine(TestController.java:46) 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:190) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) at javax.servlet.http.HttpServlet.service(HttpServlet.java:497) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) at javax.servlet.http.HttpServlet.service(HttpServlet.java:584) at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129) at org.springblade.core.log.filter.LogTraceFilter.doFilter(LogTraceFilter.java:39) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at org.springblade.core.boot.request.BladeRequestFilter.doFilter(BladeRequestFilter.java:58) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84) at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62) at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68) at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68) at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:111) at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46) at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64) at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60) at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77) at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269) at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78) at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133) at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130) at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48) at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43) at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249) at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78) at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99) at io.undertow.server.Connectors.executeRootHandler(Connectors.java:390) at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:836) at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35) at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2019) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1558) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1449) at java.lang.Thread.run(Thread.java:750)
五、若有更多详细信息,请在下面提供。
附件1:(上面篇幅限制,完整的错误堆栈在这个附件里面!!)
附件2:(我这个工程跑同样的测试代码,是能成功的!!)
我的判断:底层的 SqlParser 无法识别 TDengine 的关键字 stable
扫一扫访问 Blade技术社区 移动端