当前位置: 首页 > news >正文

一二三应用开发平台——能力扩展:多数据源支持

背景

随着项目规模的扩大,单一数据源已无法满足复杂业务需求,多数据源应运而生。

技术选型

MyBatis-Plus 的官网提供了两种多数据源扩展插件:开源生态的 <font style="color:rgb(53, 56, 65);">dynamic-datasource</font> 和 企业级生态的 <font style="color:rgb(53, 56, 65);">mybatis-mate</font>

这里遵循开源免费的原则,选择前者dynamic-datasource,集成到平台中来。

dynamic-datasource

<font style="color:rgb(53, 56, 65);">dynamic-datasource</font> 是一个开源的 Spring Boot 多数据源启动器,提供了丰富的功能,包括数据源分组、敏感信息加密、独立初始化表结构等。

  • 数据源分组:适用于多种场景,如读写分离、一主多从等。
  • 敏感信息加密:使用 <font style="color:rgb(53, 56, 65);">ENC()</font> 加密数据库配置信息。
  • 独立初始化:支持每个数据库独立初始化表结构和数据库。
  • 自定义注解:支持自定义注解,需继承 <font style="color:rgb(53, 56, 65);">DS</font>
  • 简化集成:提供对 Druid、HikariCP 等连接池的快速集成。
  • 组件集成:支持 Mybatis-Plus、Quartz 等组件的集成方案。
  • 动态数据源:支持项目启动后动态增加或移除数据源。
  • 分布式事务:提供基于 Seata 的分布式事务方案。

实现

添加maven依赖

首先需要考虑的把依赖加到哪个模块下。数据源属于底层实现,平台的核心模块如system、support、entity-config,以及能力扩展模块,如mail、notification等,还有基于平台构建的业务功能模块,都有可能在某些特定情况下使用不同的数据源。

因此,将其放在平台最底层的common模块中加载最合理。

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>4.3.1</version>
</dependency>

注意,开发平台使用的spring boot版本是2.3.0,因此使用的dynamic-datasource组件对应是dynamic-datasource-spring-boot-starter,如果对应的spring boot版本是3.x,则需要使用dynamic-datasource-spring-boot3-starter。

配置数据源

修改yml配置,官方示例如下:

spring:
  datasource:
    dynamic:
      primary: master
      strict: false
      datasource:
        master:
          url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
        slave_1:
          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
        slave_2:
          url: ENC(xxxxx)
          username: ENC(xxxxx)
          password: ENC(xxxxx)
          driver-class-name: com.mysql.jdbc.Driver

官方示例没有给出druid的相关处理,到dynamic-datasource的官网查看,如何集成druid,居然需要付费查看???

然后通过ai和百度,参照配置druid如下:

spring:
  datasource:
    dynamic:
      primary: master # 设置默认数据源
      strict: false   # 是否严格匹配数据源
      datasource:
        # 主库数据源
        master:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/abc?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&allowMultiQueries=true
          username: root
          password: root
          druid:
            # 连接池的配置信息
            # 初始化大小,最小,最大
            initial-size: 5
            min-idle: 5
            maxActive: 20
            # 配置获取连接等待超时的时间
            maxWait: 60000
            # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
            timeBetweenEvictionRunsMillis: 60000
            # 配置一个连接在池中最小生存的时间,单位是毫秒
            minEvictableIdleTimeMillis: 120000
            # 检测连接是否有效使用的sql语句
            validationQuery: SELECT 1
            # 空闲时检测连接有效性
            testWhileIdle: true
            # 申请时检测连接有效性
            testOnBorrow: false
            # 归还时检测连接有效性
            testOnReturn: false
            # 连接池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作。实际项目中建议配置成true
            keepAlive: true
            # 配置监控统计拦截的filters
            filters: mergeStat
            # 配置web监控
            web-stat-filter:
              enabled: true
              url-pattern: "/*"
              exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
            # 配置监控页面
            stat-view-servlet:
              enabled: true
              url-pattern: "/druid/*"
              # 登录名
              login-username: admin
              # 登录密码
              login-password: 1234@lwq
              # IP白名单(没有配置或者为空,则允许所有访问)
              allow:
              # IP黑名单 (共同存在时,deny优先于allow)
              deny:

启动项目,查看日志输出,发现druid连接池并没有生效,使用的是SpringBoot默认的HikariDataSource连接池如下:

08:30:39.771 INFO  [main ] com.zaxxer.hikari.HikariDataSource - master - Starting...
08:30:40.101 INFO  [main ] com.zaxxer.hikari.HikariDataSource - master - Start completed.

查阅了大量资料,尝试更换了N种配置法,更换了N个druid、dynamic-datasource的版本,都无法正常使用,要么像上面一样,使用的不是druid连接池,要么是启动环节报错,配置项解析无效。

在上面花费了大量时间,没有结果,在这里吐槽一句,作为一个插件,如何配置druid连接池要付费29.9才能查看文档,并且即使付了费,也不一定解决问题,这就比较坑了。

不死心,去翻源码,发现包com.baomidou.dynamic.datasource.creator下的DataSourceProperty.java中有这么一句:

又经过了反复尝试和验证,把druid-starter的版本号,从1.2.18,降低到了1.1.10才生效。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>

这时候的启动信息看上去正常了,如下:

11:24:25.549 WARN  [main ] com.baomidou.dynamic.datasource.creator.druid.DruidDataSourceCreator - dynamic-datasource current not support [mergeStat]
11:24:25.973 INFO  [main ] com.alibaba.druid.pool.DruidDataSource - {dataSource-1,master} inited
11:24:25.977 INFO  [main ] com.baomidou.dynamic.datasource.DynamicRoutingDataSource - dynamic-datasource - add a datasource named [master] success
11:24:25.978 INFO  [main ] com.baomidou.dynamic.datasource.DynamicRoutingDataSource - dynamic-datasource initial loaded [1] datasource,primary datasource named [master]

在原来基础上,增加一套数据库配置进行验证,如下:

  datasource:
    dynamic:
      primary: master # 设置默认数据源
      strict: false   # 是否严格匹配数据源
      datasource:
        # 主库数据源
        master:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/abc?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&allowMultiQueries=true
          username: root
          password: root
        meet:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/meet?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&allowMultiQueries=true
          username: root
          password: root

启动时,控制台输出如下:

11:32:47.234 WARN  [main ] com.baomidou.dynamic.datasource.creator.druid.DruidDataSourceCreator - dynamic-datasource current not support [mergeStat]
11:32:47.743 INFO  [main ] com.alibaba.druid.pool.DruidDataSource - {dataSource-1,meet} inited
11:32:47.746 WARN  [main ] com.baomidou.dynamic.datasource.creator.druid.DruidDataSourceCreator - dynamic-datasource current not support [mergeStat]
11:32:47.776 INFO  [main ] com.alibaba.druid.pool.DruidDataSource - {dataSource-2,master} inited
11:32:47.777 INFO  [main ] com.baomidou.dynamic.datasource.DynamicRoutingDataSource - dynamic-datasource - add a datasource named [meet] success
11:32:47.777 INFO  [main ] com.baomidou.dynamic.datasource.DynamicRoutingDataSource - dynamic-datasource - add a datasource named [master] success
11:32:47.777 INFO  [main ] com.baomidou.dynamic.datasource.DynamicRoutingDataSource - dynamic-datasource initial loaded [2] datasource,primary datasource named [master]

默认使用的是master数据源,所以平台原有功能未受影响。

然后把druid的版本换回1.2.18,居然发现也正常了,这就非常诡异了……反复清理与编译,问题没有重现。

但是验证到druid内置监控器的时候,发现无法正常访问了,改回1.1.10版本则恢复正常。

整理一下最终测试有效的各组件版本及配置如下:

SpringBoot 2.3.0.REALEASE

dynamic-datasource版本4.3.1

<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
  <version>4.3.1</version>
</dependency>

druid-spring-boot-starter版本1.1.10,如下:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>

系统yml配置文件多数据源相关如下:

#数据连接
spring:
  datasource:
    dynamic:
      primary: master # 设置默认数据源
      strict: false   # 是否严格匹配数据源
      datasource:
        # 主库数据源
        master:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/abc?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&allowMultiQueries=true
          username: root
          password: root
        meet:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/meet?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&allowMultiQueries=true
          username: root
          password: root
      druid:
        # 连接池的配置信息
        # 初始化大小,最小,最大
        initial-size: 5
        min-idle: 5
        maxActive: 20
        # 配置获取连接等待超时的时间
        maxWait: 60000
        # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
        timeBetweenEvictionRunsMillis: 60000
        # 配置一个连接在池中最小生存的时间,单位是毫秒
        minEvictableIdleTimeMillis: 120000
        # 检测连接是否有效使用的sql语句
        validationQuery: SELECT 1
        # 空闲时检测连接有效性
        testWhileIdle: true
        # 申请时检测连接有效性
        testOnBorrow: false
        # 归还时检测连接有效性
        testOnReturn: false
        # 连接池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作。实际项目中建议配置成true
        keepAlive: true
        # 配置监控统计拦截的filters
        filters: mergeStat
        # 配置web监控
        web-stat-filter:
          enabled: true
          url-pattern: "/*"
          exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
        # 配置监控页面
        stat-view-servlet:
          enabled: true
          url-pattern: "/druid/*"
          # 登录名
          login-username: admin
          # 登录密码
          login-password: 1234@lwq
          # IP白名单(没有配置或者为空,则允许所有访问)
          allow:
          # IP黑名单 (共同存在时,deny优先于allow)
          deny: 
  

这里其实还有一个问题,两个数据源,本打算配置多个druid的监控了,实际测试发现,把druid配置放在各个数据源配置项下,并不会生效,只有放在最外层,如上图所示,才可以正常打开监控页面,并且监控的是master主数据库的监控。可以通过修改primary,指向meet数据库,从而监控的数据源也发生了变化。实际上,同一时间段,durid只监控一个数据源,先前的想法,为不同的数据源配置不同的监控页面应该是不可行的。

此外,网上查到的大量问题提到,需要将druid的自动化配置排除,在yml配置中移除,如下:

spring:
  autoconfigure:  
    exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
  datasource:
   ……

或者在SpringBoot启动类注解中配置exclude = {DataSourceAutoConfiguration.class}移除,如下:

@SpringBootApplication(scanBasePackages = "tech.abc", exclude = {DataSourceAutoConfiguration.class})
@MapperScan("tech.abc.**.mapper")
@EnableConfigurationProperties({PlatformConfig.class, AppConfig.class})
@Slf4j
@EnableRetry
public class PlatformBootApplication implements CommandLineRunner {

在以上版本中测试中并不需要,推测很可能是dynamic-datasource历史上某些版本需要这么操作。

通过注解指定数据源

上面经历了很多曲折,接下来的事情就简单了,主数据源作为默认,不用做任何额外的工作。

某些实体服务需要使用其他数据源,在对应的服务实现类ServiceImpl中添加注解@DS(“数据源名称”),这里的数据源名称对应着yml文件中配置的数据源,然后就可以了。

示例如下:

package tech.abc.dynamicdatasource;

import com.baomidou.dynamic.datasource.annotation.DS;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import tech.abc.dynamicdatasource.mapper.TaskCategoryMapper;
import tech.abc.platform.common.base.BaseServiceImpl;

/**
 * @author wqliu
 * @date 2025-03-09
 */
@DS("meet")
@Slf4j
@Service
public class TaskCategoryServiceImpl extends BaseServiceImpl<TaskCategoryMapper, TaskCategory> implements TaskCategoryService {
    public void test() {
        long count = this.count();
        log.info("count:{}", count);
    }
}

在启动类里调用了以下方法进行测试,如下:

@Override
public void run(String... ) throws Exception {
    // 启动消息服务端
    startMessageServer();
    taskCategoryService.test();
}

控制台输出日志,功能正常,如下:

10:28:48.720 INFO  [main ] tech.abc.dynamicdatasource.TaskCategoryServiceImpl - count:10

新问题及解决

按照上述模式实现了多数据源功能后,在平台功能测试环节发现出了问题,系统可以正常启动,无报错,但是登录环节,查询用户数据时,提示无法获取到create_time字段,如下所示:

### Error querying database.  Cause: org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'create_time' from result set.  Cause: java.sql.SQLFeatureNotSupportedException
; null; nested exception is java.sql.SQLFeatureNotSupportedException
### Cause: org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'create_time' from result set.  Cause: java.sql.SQLFeatureNotSupportedException
; null; nested exception is java.sql.SQLFeatureNotSupportedException
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:156)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:142)
	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:425)
	... 62 common frames omitted
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'create_time' from result set.  Cause: java.sql.SQLFeatureNotSupportedException
; null; nested exception is java.sql.SQLFeatureNotSupportedException
	at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96)
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
	at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:92)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:439)
	at com.sun.proxy.$Proxy89.select(Unknown Source)
	at org.mybatis.spring.SqlSessionTemplate.select(SqlSessionTemplate.java:248)
	at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeWithResultHandler(MybatisMapperMethod.java:155)
	at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:74)
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:152)
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89)
	at com.sun.proxy.$Proxy171.selectList(Unknown Source)
	at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:227)
	at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:627)
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:166)
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89)
	at com.sun.proxy.$Proxy171.selectOne(Unknown Source)
	at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:214)
	at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:627)
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:166)
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89)
	at com.sun.proxy.$Proxy171.selectOne(Unknown Source)
	at com.baomidou.mybatisplus.extension.conditions.query.ChainQuery.lambda$one$cd9f9c92$1(ChainQuery.java:59)
	at com.baomidou.mybatisplus.extension.conditions.ChainWrapper.execute(ChainWrapper.java:63)
	at com.baomidou.mybatisplus.extension.conditions.query.ChainQuery.one(ChainQuery.java:59)
	at com.baomidou.mybatisplus.extension.conditions.query.ChainQuery.oneOpt(ChainQuery.java:69)
	at tech.abc.platform.entityconfig.service.impl.EntityModelDataPermissionServiceImpl.getDataPermissionSqlPart(EntityModelDataPermissionServiceImpl.java:118)
	at tech.abc.platform.entityconfig.service.impl.EntityModelDataPermissionServiceImpl$$FastClassBySpringCGLIB$$1a9fef99.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:687)
	at tech.abc.platform.entityconfig.service.impl.EntityModelDataPermissionServiceImpl$$EnhancerBySpringCGLIB$$17a19d87.getDataPermissionSqlPart(<generated>)
	at tech.abc.platform.framework.extension.MyDataPermissionHandler.getSqlSegment(MyDataPermissionHandler.java:42)
	at com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor.buildTableExpression(DataPermissionInterceptor.java:146)
	at com.baomidou.mybatisplus.extension.plugins.inner.BaseMultiTableInnerInterceptor.lambda$builderExpression$3(BaseMultiTableInnerInterceptor.java:386)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:566)
	at com.baomidou.mybatisplus.extension.plugins.inner.BaseMultiTableInnerInterceptor.builderExpression(BaseMultiTableInnerInterceptor.java:388)
	at com.baomidou.mybatisplus.extension.plugins.inner.BaseMultiTableInnerInterceptor.processPlainSelect(BaseMultiTableInnerInterceptor.java:113)
	at com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor.setWhere(DataPermissionInterceptor.java:101)
	at com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor.processSelect(DataPermissionInterceptor.java:85)
	at com.baomidou.mybatisplus.extension.parser.JsqlParserSupport.processParser(JsqlParserSupport.java:90)
	at com.baomidou.mybatisplus.extension.parser.JsqlParserSupport.parserSingle(JsqlParserSupport.java:49)
	at com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor.beforeQuery(DataPermissionInterceptor.java:64)
	at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:78)
	at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:59)
	at com.sun.proxy.$Proxy193.query(Unknown Source)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:154)
	... 69 common frames omitted
Caused by: java.sql.SQLFeatureNotSupportedException: null
	at com.alibaba.druid.pool.DruidPooledResultSet.getObject(DruidPooledResultSet.java:1771)
	at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:39)
	at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:29)
	at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:86)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:582)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:412)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:362)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:333)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:309)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:202)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:66)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:80)
	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.Plugin.invoke(Plugin.java:61)
	at com.sun.proxy.$Proxy194.query(Unknown Source)
	at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:65)
	at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:333)
	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:158)
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:110)
	at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81)
	at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:59)
	at com.sun.proxy.$Proxy193.query(Unknown Source)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:154)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.select(DefaultSqlSession.java:174)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.select(DefaultSqlSession.java:164)
	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:425)
	... 116 common frames omitted

从错误日志来推测,很像是druid的版本比较低,对于LocalDateTime类型无法正常识别和转换。

然后将druid版本,升级为1.2.18,启动正常,功能正常,但druid监控功能无法打开。
后来又尝试了1.2.1,1.1.21这两个版本,跟1.2.18版本的效果一样,未找到一个可以二者兼顾的版本。
综合考虑下,将版本设置为了较新的1.2.18,优先保证多数据源功能正常。如果项目中没用到多数据源功能,更希望使用durid监控功能,则建议将版本设置为1.1.10。

开源平台资料

平台名称:一二三应用开发平台
简介: 企业级通用低代码应用开发平台,免费全开源可商用
设计资料:csdn专栏
开源地址:Gitee
开源协议:MIT

如果您在阅读本文时获得了帮助或受到了启发,我衷心希望您能够喜欢并收藏这篇文章,为它点赞,并在评论区与我分享您的想法和心得。让我们一起交流学习,不断进步,遇见更加优秀的自己!

相关文章:

  • 模板方法模式的C++实现示例
  • React基础之项目实战
  • 贵工程寝室报修系统的设计与实现
  • JavaScript 变量与常量全面解析
  • 在线程间共享数据_第三章_《C++并发编程》笔记
  • 什么是Flask
  • spring6概述
  • HTML 基础
  • el-pagination的使用说明
  • STM32---FreeRTOS消息队列
  • HarmonyOS学习第18天:多媒体功能全解析
  • day19-前端Web——Vue3+TS+ElementPlus
  • vue3 二次封装uni-ui中的组件,并且组件中有 v-model 的解决方法
  • 三级缓存架构
  • 2025解决软件供应链安全,开源安全的版本答案:SCA+SBOM
  • 基于DeepSeek,构建个人本地RAG知识库
  • 机电公司管理信息系统小程序+论文源码调试讲解
  • Qt 中实现自定义控件子类化
  • 行为模式---观察者模式
  • 如何理解JS的异步?
  • 又有明星分析师晋升管理层:“白金分析师”武超则已任中信建投证券党委委员
  • 国家发改委:内卷式竞争扭曲市场机制、扰乱公平竞争秩序,必须整治
  • 大语言模型在线辩论说服力比人类辩手高出64%
  • 多家国有大行存款利率即将迎来新一轮下调
  • 特朗普与普京开始进行电话会谈,稍后还将致电泽连斯基
  • 红星控股重整期间实控人被留置后续:重整草案不会修改,涉车建兴职责已调整