当前位置: 首页 > 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: masterstrict: falsedatasource:master:url: jdbc:mysql://xx.xx.xx.xx:3306/dynamicusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driverslave_1:url: jdbc:mysql://xx.xx.xx.xx:3307/dynamicusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driverslave_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.Driverurl: jdbc:mysql://localhost:3306/abc?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&allowMultiQueries=trueusername: rootpassword: rootdruid:# 连接池的配置信息# 初始化大小,最小,最大initial-size: 5min-idle: 5maxActive: 20# 配置获取连接等待超时的时间maxWait: 60000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒timeBetweenEvictionRunsMillis: 60000# 配置一个连接在池中最小生存的时间,单位是毫秒minEvictableIdleTimeMillis: 120000# 检测连接是否有效使用的sql语句validationQuery: SELECT 1# 空闲时检测连接有效性testWhileIdle: true# 申请时检测连接有效性testOnBorrow: false# 归还时检测连接有效性testOnReturn: false# 连接池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作。实际项目中建议配置成truekeepAlive: true# 配置监控统计拦截的filtersfilters: mergeStat# 配置web监控web-stat-filter:enabled: trueurl-pattern: "/*"exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"# 配置监控页面stat-view-servlet:enabled: trueurl-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.Driverurl: jdbc:mysql://localhost:3306/abc?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&allowMultiQueries=trueusername: rootpassword: rootmeet:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/meet?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&allowMultiQueries=trueusername: rootpassword: 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.Driverurl: jdbc:mysql://localhost:3306/abc?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&allowMultiQueries=trueusername: rootpassword: rootmeet:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/meet?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&allowMultiQueries=trueusername: rootpassword: rootdruid:# 连接池的配置信息# 初始化大小,最小,最大initial-size: 5min-idle: 5maxActive: 20# 配置获取连接等待超时的时间maxWait: 60000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒timeBetweenEvictionRunsMillis: 60000# 配置一个连接在池中最小生存的时间,单位是毫秒minEvictableIdleTimeMillis: 120000# 检测连接是否有效使用的sql语句validationQuery: SELECT 1# 空闲时检测连接有效性testWhileIdle: true# 申请时检测连接有效性testOnBorrow: false# 归还时检测连接有效性testOnReturn: false# 连接池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作。实际项目中建议配置成truekeepAlive: true# 配置监控统计拦截的filtersfilters: mergeStat# 配置web监控web-stat-filter:enabled: trueurl-pattern: "/*"exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"# 配置监控页面stat-view-servlet:enabled: trueurl-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.DruidDataSourceAutoConfiguredatasource:……

或者在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.SQLFeatureNotSupportedExceptionat 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.SQLFeatureNotSupportedExceptionat 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: nullat 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

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

相关文章:

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

背景 随着项目规模的扩大&#xff0c;单一数据源已无法满足复杂业务需求&#xff0c;多数据源应运而生。 技术选型 MyBatis-Plus 的官网提供了两种多数据源扩展插件&#xff1a;开源生态的 <font style"color:rgb(53, 56, 65);">dynamic-datasource</fon…...

pandas-基础(数据结构及文件访问)

1 Pandas的数据结构 1.1 Series 特点&#xff1a;一维的数据型对象&#xff0c;包含一个值序列和数据标签(即索引&#xff09; 创建Series&#xff1a; pandas.Series(dataNone, indexNone, dtypeNone, nameNone, copyFalse, fastpathFalse) 参数说明&#xff1a; data&a…...

数据分析与AI丨AI Fabric:数据和人工智能架构的未来

AI Fabric 架构是模块化、可扩展且面向未来的&#xff0c;是现代商业环境中企业实现卓越的关键。 在当今商业环境中&#xff0c;数据分析和人工智能领域发展可谓日新月异。几乎每天都有新兴技术诞生&#xff0c;新的应用场景不断涌现&#xff0c;前沿探索持续拓展。可遗憾的是&…...

如何根据应用需求选择光谱相机

一、按核心参数匹配需求 ‌光谱范围‌ ‌农业监测‌&#xff1a;需覆盖可见光至近红外&#xff08;400-1000nm&#xff09;&#xff0c;以捕捉作物叶绿素、水分等特征‌。 ‌地质勘探‌&#xff1a;需宽光谱&#xff08;350-2500nm&#xff09;及高分辨率&#xff08;3-10nm…...

内存泄漏出现的时机和原因,如何避免?

由于时间比较紧张我就不排版了&#xff0c;但是对于每一种可能的情况都会出对应的代码示例以及解决方案代码示例。 内存泄漏可能的原因之一在于用户在动态分配一个内存空间之中&#xff0c;忘记将这部分内容手动释放。例如&#xff1a;&#xff08;c之中使用new分配内存没有使…...

Python第十六课:深度学习入门 | 神经网络解密

🎯 本节目标 理解生物神经元与人工神经网络的映射关系掌握激活函数与损失函数的核心作用使用Keras构建手写数字识别模型可视化神经网络的训练过程掌握防止过拟合的基础策略一、神经网络基础(大脑的数字化仿生) 1. 神经元对比 生物神经元人工神经元树突接收信号输入层接收特…...

从0到1,带你开启TypeScript的奇妙之旅

目录 一、TypeScript 是什么? 二、为什么要学习 TypeScript? 三、快速上手:环境搭建与 Hello World (一)安装 TypeScript (二)创建第一个 TypeScript 文件 (三)编译 TypeScript 文件 (四)运行编译后的 JavaScript 文件 四、深入 TypeScript 核心语法 (一)…...

如何修复“RPC 服务器不可用”错误

远程过程调用&#xff08;Remote Procedure Call&#xff0c; RPC&#xff09;是允许客户端在不同计算机上执行进程的众多可用网络进程之一。本文将深入探讨RPC如何在不同的软件系统之间实现无缝消息交换&#xff0c;同时重点介绍与RPC相关的常见错误的一些原因。 什么是远程过…...

【redis】五种数据类型和编码方式

文章目录 五种数据类型编码方式stringhashlistsetzset查询内部编码 五种数据类型 字符串&#xff1a;Java 中的 String哈希&#xff1a;Java 中的 HashMap列表&#xff1a;Java 中的 List集合&#xff1a;Java 中的 Set有序集合&#xff1a;除了存 member 之外&#xff0c;还有…...

今日头条文章爬虫教程

今日头条文章爬虫教程 随着互联网的发展&#xff0c;新闻资讯类平台如今日头条积累了海量的数据。对于数据分析师、研究人员等群体来说&#xff0c;获取这些数据进行分析和研究具有重要的价值。本文将介绍如何使用Python编写爬虫&#xff0c;爬取今日头条的文章数据。 一、准…...

使用Modelsim手动仿真

FPGA设计流程 在设计输入之后,设计综合前进行 RTL 级仿真,称为综合前仿真,也称为前仿真或 功能仿真。前仿真也就是纯粹的功能仿真,主旨在于验证电路的功能是否符合设计要求,其特点是不考虑电路门延迟与线延迟。在完成一个设计的代码编写工作之后,可以直接对代码进行仿真,…...

从Manus看网络安全:通用AI智能体重构安全运营

当通用AI智能体遇见网络安全 开启主动防御的跃迁 在勒索软件平均潜伏期缩短至3.7天、APT攻击复杂度指数级攀升的当下&#xff0c;传统SOAR产品&#xff08;安全编排、自动化和响应&#xff09;正面临两大困境&#xff1a; 规则依赖症&#xff1a;基于Playbook的响应逻辑&…...

南开提出1Prompt1Story,无需训练,可通过单个连接提示实现一致的文本到图像生成。

&#xff08;1Prompt1Story&#xff09;是一种无训练的文本到图像生成方法&#xff0c;通过整合多个提示为一个长句子&#xff0c;并结合奇异值重加权&#xff08;SVR&#xff09;和身份保持交叉注意力&#xff08;IPCA&#xff09;技术&#xff0c;解决了生成图像中身份不一致…...

hooks useModule自定义hooks (二次封装AgGridReact ag-table)自定义表头,自定义表头搜索

场景业务&#xff1a; 多次运用AgGridReact的table 列表 思路&#xff1a; 运用自定义hooks进行二次封装&#xff1a; 通用配置例如&#xff1a;传参的参数&#xff0c;传参的url&#xff0c;需要缓存的key这些键值类 定制化配置例如&#xff1a;需要对table 的一些定制化传…...

Manus无需邀请码即可使用的平替方案-OpenManus实测

文章目录 Manus 简介核心定位技术架构核心特点应用场景性能表现用户体验发展计划OpenManus技术架构与设计理念核心功能特性应用场景案例与闭源Manus的差异对比安装使用与实战演示执行过程记录简单案例-快速写一个helloworld的java程序复杂案例-分析特斯拉汽车近三年财务数据并生…...

常用的gpt

1、DeepSeek 好用。可惜现在热度上去了&#xff0c;经常查技术问题会报网络繁忙 2、Qwen Chat Qwen Chat 千问&#xff0c;阿里的gpt。需要注册账号&#xff0c;好用程度感觉跟deepSeek差不多。并且不会像deepSeek一样报网络繁忙 3、文心一样 百度的。相对上2个技术问题较弱…...

【AI】【Unity】关于Unity接入DeepseekAPI遇到的坑

前言 由于deepseek网页端在白天日常抽风&#xff0c;无法正常的使用&#xff0c;所以调用API就成了目前最好的选择&#xff0c;尤其是Deepseek的API价格低得可怕&#xff0c;这不是和白送的一样吗&#xff01;然后使用过很多本地部署接入API的方式&#xff0c;例如Chatbox、Pa…...

MAX232数据手册:搭建电平转换桥梁,助力串口稳定通信

在现代电子设备的通信领域&#xff0c;串口通信因其简单可靠而被广泛应用。MAX232 芯片作为串口通信中的关键角色&#xff0c;发挥着不可或缺的作用。下面&#xff0c;我们将依据提供的资料&#xff0c;深入解读 MAX232 芯片的各项特性、参数以及应用要点。 一、引脚说明 MAX2…...

vue2项目开启br压缩

<在 Vue 2 项目中&#xff0c;使用 br 压缩通常是为了减少文件大小&#xff0c;从而加快网页加载速度。br 是一种由 Google 开发的压缩格式&#xff0c;全称为 Brotli。在 Vue 2 项目中&#xff0c;你可以通过配置构建工具&#xff08;如 Webpack&#xff09;来启用对 .br 文…...

jdk-21_linux-x64_bin.tar.gz Linux jdk21压缩包安装保姆级(详细安装教程)

jdk-21_linux-x64_bin.tar.gz 解压版详细安装教程 一、简洁版&#xff08;需要对 Linux 操作有一定基础&#xff09;二、图文详细教程1、前置准备2、解压安装3、配置环境变量4、验证成功 官网下载地址&#xff1a; https://www.oracle.com/java/technologies/downloads/#java2…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...