bladex-boot 配置多数据源连 TDengine 执行建表报错 ParseException

Blade 未结 4 1834
kelchoi
kelchoi 剑圣 2022-05-31 22:55
悬赏:5

一、该问题的重现步骤是什么?


1、下载一份新的 bladex-boot 的代码,版本为 2.9.1


2、在工程 pom.xml 文件中加入 TDengine 驱动的依赖,版本为 2.0.38,如下:

<!-- TDengine 驱动 -->
<dependency>
  <groupId>com.taosdata.jdbc</groupId>
  <artifactId>taos-jdbcdriver</artifactId>
  <version>2.0.38</version>
</dependency>


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

其中配置文件如何配置,参考:

  1. dynamic-datasource-spring-boot-starter 的文档:https://baomidou.com/pages/a61e1b/

  2. druid 文档关于多数据源配置的说明:https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter#如何配置多数据源


5、编写两个测试接口,一个测试创建 MySQL 的表,另一个测试创建 TDengine 的表。代码如下图,是一个简单的三层结构的代码:



其中,关键的代码如下:


StudentMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.springblade.modules.demo.mapper.StudentMapper">

    <update id="dropTable">
        drop table if exists biz_student;
    </update>

    <update id="createTable">
        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='用户表';
    </update>

</mapper>

MeterMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.springblade.modules.demo.mapper.MeterMapper">

    <update id="dropSuperTable">
        drop stable if exists meter;
    </update>

    <update id="createSuperTable">
        CREATE stable meter (
            ts timestamp,
            a int,
            b int
        ) TAGS (
            x int,
            y int
        );
    </update>

</mapper>

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(<generated>)
	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(<generated>)
	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:(上面篇幅限制,完整的错误堆栈在这个附件里面!!)

完整的日志和报错信息.txt


附件2:(我这个工程跑同样的测试代码,是能成功的!!)

自己建的测试工程.zip


我的判断:底层的 SqlParser 无法识别 TDengine 的关键字 stable




4条回答
  • 2022-06-06 18:23

    官方的说mybatis-plus不支持taos纯属瞎扯,别的框架都可以

    1 讨论(0)
  • 框架用的mybatis plus,mybatis plus目前只支持如下数据库:

    BTTECI(N(9@HDXG$%95`274.png

    作者追问:2022-06-01 12:50

    我附件2有自己测试的工程代码,我自己搭建的是可以跑得通的。都是用 mybatis plus。而同样的库、同样的版本、同样的测试代码,在 bladex-boot 里面跑不通。

    0 讨论(2)
  • 2022-06-17 15:38
    Mapper类\方法 增加
    @InterceptorIgnore(tenantLine = "true")


    0 讨论(0)
  • 2022-07-15 09:31

    请问楼主解决了没

    https://github.com/taosdata/TDengine/issues/12618

    0 讨论(0)
提交回复