Spring Boot 2.5.x及以上搭配MariaDB驱动出现连接关闭异常
Spring Cloud Data Flow部署后Spring Boot 2.5.x+应用数据库连接错误排查
部署背景
通过Helm在Kubernetes集群部署SCDF,使用外部AWS RDS MySQL数据库,部署命令如下:
helm3 --kube-context my-cluster install my-release bitnami/spring-cloud-dataflow --namespace my-namespace \ --set server.service.type=NodePort \ --set server.image.tag=2.9.2-debian-10-r0 \ --set rabbitmq.enabled=false \ --set kafka.enabled=false \ --set skipper.enabled=false \ --set mariadb.enabled=false \ --set 'externalDatabase.dataflow.url=jdbc:mysql://****.****.rds.amazonaws.com:3306/dataflow?useSSL=false' \ --set usePipelineAuth=false \ --set useBatchMultiSend=false \ --set allowPublicKeyRetrieval=true \ --set externalDatabase.dataflow.username=username \ --set externalDatabase.password=pwd \ --set externalDatabase.driver=org.mariadb.jdbc.Driver \ --set server.configuration.batchEnabled=true \ --set server.configuration.streamingEnabled=false \ --set server.livenessProbe.enabled=false \ --set server.readinessProbe.enabled=false \ --set externalDatabase.hibernateDialect=org.hibernate.dialect.MySQL5Dialect \ --set server.resources.limits.memory=16Gi \ --set server.resources.limits.cpu=15 \ --set server.resources.requests.memory=2Gi \ --set server.resources.requests.cpu=1000m \ --set server.ingress.enabled=true \ --set server.ingress.hostname=lab-development-dataflow-v2.dev.miqdigital.com \ --set server.ingress.ingressClassName= \ --set server.ingress.apiVersion=networking.k8s.io/v1 \ --set server.composedTaskRunner.image.tag=2.9.2-debian-10-r0 \ --set deployer.environmentVariables=SPRING_PROFILES_ACTIVE=integration \ --set deployer.resources.limits.cpu=2 \ --set deployer.resources.limits.memory=6Gi \ --set deployer.resources.requests.cpu=0.5 \ --set deployer.resources.requests.memory=2Gi \ --set deployer.podSecurityContext.runAsUser=0
问题现象
SCDF中注册的Spring Boot 2.1.x版本应用可正常运行,但2.5.x及以上版本启动时出现数据库连接错误,无法初始化EntityManagerFactory。
错误日志
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. [ERROR] 2022-09-20 07:41:08 [main ] [/] [] SpringApplication:865 - Application run failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to open JDBC Connection for DDL execution at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1154) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:908) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:448) at org.springframework.boot.SpringApplication.run(SpringApplication.java:339) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1365) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354) at com.miq.dsp.batch.DspBatchApplication.main(DspBatchApplication.java:27) 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.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88) Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to open JDBC Connection for DDL execution at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:421) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) ... 23 common frames omitted Caused by: org.hibernate.exception.JDBCConnectionException: Unable to open JDBC Connection for DDL execution at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:48) at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99) at org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl.getIsolatedConnection(DdlTransactionIsolatorNonJtaImpl.java:69) at org.hibernate.tool.schema.internal.exec.ImprovedExtractionContextImpl.getJdbcConnection(ImprovedExtractionContextImpl.java:60) at org.hibernate.tool.schema.internal.exec.ImprovedExtractionContextImpl.getJdbcDatabaseMetaData(ImprovedExtractionContextImpl.java:67) at org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl.getTables(InformationExtractorJdbcDatabaseMetaDataImpl.java:333) at org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl.getTablesInformation(DatabaseInformationImpl.java:120) at org.hibernate.tool.schema.internal.GroupedSchemaValidatorImpl.validateTables(GroupedSchemaValidatorImpl.java:39) at org.hibernate.tool.schema.internal.AbstractSchemaValidator.performValidation(AbstractSchemaValidator.java:89) at org.hibernate.tool.schema.internal.AbstractSchemaValidator.doValidation(AbstractSchemaValidator.java:68) at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:192) at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:73) at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:318) at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:468) at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1259) at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58) at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ... 27 common frames omitted Caused by: java.sql.SQLNonTransientConnectionException: Could not connect to address=(host=****My_DB_URL****)(port=3306)(type=master) : (conn=11812758) could not load system variables at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.createException(ExceptionFactory.java:73) at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.create(ExceptionFactory.java:197) at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.connectWithoutProxy(AbstractConnectProtocol.java:1394) at org.mariadb.jdbc.internal.util.Utils.retrieveProxy(Utils.java:635) at org.mariadb.jdbc.MariaDbConnection.newConnection(MariaDbConnection.java:150) at org.mariadb.jdbc.Driver.connect(Driver.java:89) at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138) at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:364) at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:206) at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:476) at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561) at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:115) at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:180) at org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl.getIsolatedConnection(DdlTransactionIsolatorNonJtaImpl.java:43) ... 42 common frames omitted Caused by: java.sql.SQLNonTransientConnectionException: (conn=11812758) could not load system variables at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.createException(ExceptionFactory.java:73) at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.create(ExceptionFactory.java:188) at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.requestSessionDataWithShow(AbstractConnectProtocol.java:1114) at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.readPipelineAdditionalData(AbstractConnectProtocol.java:1075) at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.postConnectionQueries(AbstractConnectProtocol.java:885) at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.createConnection(AbstractConnectProtocol.java:600) at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.connectWithoutProxy(AbstractConnectProtocol.java:1389) ... 55 common frames omitted Caused by: java.sql.SQLNonTransientConnectionException: (conn=11812758) Connection is closed at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.createException(ExceptionFactory.java:73) at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.create(ExceptionFactory.java:192) at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.cmdPrologue(AbstractQueryProtocol.java:1946) at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.executeQuery(AbstractQueryProtocol.java:249) at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.requestSessionDataWithShow(AbstractConnectProtocol.java:1089) ... 59 common frames omitted
问题分析与解决办法
从错误日志根因来看,MariaDB JDBC驱动在尝试加载数据库系统变量时连接被关闭,结合Spring Boot版本差异,原因及解决办法如下:
1. 修正JDBC URL参数
Spring Boot 2.5.x+默认使用的MariaDB驱动版本对MySQL连接参数要求更严格,需补充参数解决时区和系统变量加载问题:
修改SCDF部署中的externalDatabase.dataflow.url为:
jdbc:mysql://****.****.rds.amazonaws.com:3306/dataflow?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false&autoReconnect=true
serverTimezone=UTC:指定时区避免时间格式不兼容useLegacyDatetimeCode=false:禁用旧日期时间处理逻辑,适配新版本驱动autoReconnect=true:连接断开时自动重连
2. 指定兼容的MariaDB驱动版本
Spring Boot 2.5.x+默认引入的MariaDB驱动版本可能与AWS RDS MySQL存在兼容性问题,在Spring Boot 2.5.x+应用的依赖管理中显式指定稳定兼容版本:
Maven:
<dependency> <groupId>org.mariadb.jdbc</groupId> <artifactId>mariadb-java-client</artifactId> <version>2.7.10</version> </dependency>
Gradle:
implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.10'
3. 检查数据库用户权限
确保连接数据库的用户拥有SHOW VARIABLES权限,驱动需要该权限加载系统变量。执行以下SQL授权:
GRANT SHOW VARIABLES ON *.* TO 'username'@'%'; FLUSH PRIVILEGES;
4. 调整Hikari连接池参数
Spring Boot 2.5.x之后Hikari连接池默认超时时间较短,在应用配置中增加连接超时时间:
spring.datasource.hikari.connection-timeout=30000 spring.datasource.hikari.max-lifetime=1800000
connection-timeout=30000:设置连接超时为30秒max-lifetime=1800000:设置连接最大存活时间为30分钟
内容的提问来源于stack exchange,提问作者debashree
相关产品推荐
相关产品推荐

