This is an automated email from the ASF dual-hosted git repository.
jimin pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/incubator-seata.git
The following commit(s) were added to refs/heads/2.x by this push:
new a18e999b2b bugfix: fix load driver class in Hikari (#7504)
a18e999b2b is described below
commit a18e999b2bc351c3603ec13ae5445ae8c6d6b45c
Author: maple <[email protected]>
AuthorDate: Wed Jul 9 13:39:26 2025 +0800
bugfix: fix load driver class in Hikari (#7504)
---
changes/en-us/2.x.md | 1 +
changes/zh-cn/2.x.md | 1 +
.../server/store/HikariDataSourceProvider.java | 89 +++++++++++++++++++++-
.../store/db/AbstractDataSourceProviderTest.java | 81 ++++++++++++++++++++
4 files changed, 168 insertions(+), 4 deletions(-)
diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md
index cf0fd5bae3..c2a5e50bef 100644
--- a/changes/en-us/2.x.md
+++ b/changes/en-us/2.x.md
@@ -34,6 +34,7 @@ Add changes here for all PR submitted to the 2.x branch.
- [[#7397](https://github.com/apache/incubator-seata/pull/7397)] Resolve
NullPointer and port binding errors
- [[#7502](https://github.com/apache/incubator-seata/pull/7502)] remove extra
dots and keep the naming style consistent with other tables
- [[#7498](https://github.com/apache/incubator-seata/pull/7498)] fix the class
name whitelist check issue in fury deserialization
+- [[#7504](https://github.com/apache/incubator-seata/pull/7504)] fix load
driver class in Hikari
### optimize:
diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md
index 4b2cb19ddc..e4d7d15ad3 100644
--- a/changes/zh-cn/2.x.md
+++ b/changes/zh-cn/2.x.md
@@ -34,6 +34,7 @@
- [[#7397](https://github.com/apache/incubator-seata/pull/7397)] 解决空指针和端口绑定错误
- [[#7502](https://github.com/apache/incubator-seata/pull/7502)]
删除多余点号和保持命名规范统一
- [[#7498](https://github.com/apache/incubator-seata/pull/7498)]
修复fury反序列化的类名白名单检查问题
+- [[#7504](https://github.com/apache/incubator-seata/pull/7504)] 修复 Hikari
中的加载驱动程序类
### optimize:
diff --git
a/server/src/main/java/org/apache/seata/server/store/HikariDataSourceProvider.java
b/server/src/main/java/org/apache/seata/server/store/HikariDataSourceProvider.java
index bb61adeb31..f1390e85d9 100644
---
a/server/src/main/java/org/apache/seata/server/store/HikariDataSourceProvider.java
+++
b/server/src/main/java/org/apache/seata/server/store/HikariDataSourceProvider.java
@@ -22,8 +22,16 @@ import com.zaxxer.hikari.util.IsolationLevel;
import org.apache.seata.common.ConfigurationKeys;
import org.apache.seata.common.loader.LoadLevel;
import org.apache.seata.core.store.db.AbstractDataSourceProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.DriverPropertyInfo;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties;
import static
org.apache.seata.common.DefaultValues.DEFAULT_DB_HIKARI_IDLE_TIMEOUT;
@@ -37,6 +45,8 @@ import static
org.apache.seata.common.DefaultValues.DEFAULT_DB_HIKARI_VALIDATION
@LoadLevel(name = "hikari")
public class HikariDataSourceProvider extends AbstractDataSourceProvider {
+ private static final Logger logger =
LoggerFactory.getLogger(HikariDataSourceProvider.class);
+
@Override
public DataSource doGenerate() {
Properties properties = new Properties();
@@ -52,10 +62,35 @@ public class HikariDataSourceProvider extends
AbstractDataSourceProvider {
properties.setProperty("dataSource.maintainTimeStats", "false");
HikariConfig config = new HikariConfig(properties);
- config.setDriverClassName(getDriverClassName());
- config.setJdbcUrl(getUrl());
- config.setUsername(getUser());
- config.setPassword(getPassword());
+
+ // Get the correct class loader
+ ClassLoader driverClassLoader = getDriverClassLoader();
+ String driverClassName = getDriverClassName();
+
+ // Set driver class name in the correct class loader context
+ ClassLoader originalClassLoader =
Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(driverClassLoader);
+
+ // 1. Explicitly load and register the driver
+ try {
+ Class<?> driverClass = Class.forName(driverClassName, true,
driverClassLoader);
+ Driver driver = (Driver) driverClass.newInstance();
+ DriverManager.registerDriver(new DriverWrapper(driver));
+ } catch (Exception e) {
+ logger.warn("Failed to explicitly register driver {}",
driverClassName, e);
+ }
+
+ // 2. Set configuration
+ config.setDriverClassName(driverClassName);
+ config.setJdbcUrl(getUrl());
+ config.setUsername(getUser());
+ config.setPassword(getPassword());
+
+ } finally {
+ Thread.currentThread().setContextClassLoader(originalClassLoader);
+ }
+
config.setMaximumPoolSize(getMaxConn());
config.setMinimumIdle(getMinConn());
config.setAutoCommit(true);
@@ -78,4 +113,50 @@ public class HikariDataSourceProvider extends
AbstractDataSourceProvider {
return new HikariDataSource(config);
}
+
+ /**
+ * Driver wrapper to ensure using the correct class loader
+ */
+ private static class DriverWrapper implements Driver {
+ private final Driver delegate;
+
+ public DriverWrapper(Driver delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public Connection connect(String url, Properties info) throws
SQLException {
+ return delegate.connect(url, info);
+ }
+
+ @Override
+ public boolean acceptsURL(String url) throws SQLException {
+ return delegate.acceptsURL(url);
+ }
+
+ @Override
+ public DriverPropertyInfo[] getPropertyInfo(String url, Properties
info) throws SQLException {
+ return delegate.getPropertyInfo(url, info);
+ }
+
+ @Override
+ public int getMajorVersion() {
+ return delegate.getMajorVersion();
+ }
+
+ @Override
+ public int getMinorVersion() {
+ return delegate.getMinorVersion();
+ }
+
+ @Override
+ public boolean jdbcCompliant() {
+ return delegate.jdbcCompliant();
+ }
+
+ @Override
+ public java.util.logging.Logger getParentLogger() throws
SQLFeatureNotSupportedException {
+ return delegate.getParentLogger();
+ }
+ }
}
diff --git
a/server/src/test/java/org/apache/seata/server/store/db/AbstractDataSourceProviderTest.java
b/server/src/test/java/org/apache/seata/server/store/db/AbstractDataSourceProviderTest.java
index cf8bcae149..7d992cba3d 100644
---
a/server/src/test/java/org/apache/seata/server/store/db/AbstractDataSourceProviderTest.java
+++
b/server/src/test/java/org/apache/seata/server/store/db/AbstractDataSourceProviderTest.java
@@ -33,6 +33,8 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Import;
import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
/**
*/
@@ -128,4 +130,83 @@ public class AbstractDataSourceProviderTest {
Class<?> driverClass = Class.forName(mysqlJdbcDriver, true,
classLoader);
Assertions.assertNotNull(driverClass);
}
+
+ @Test
+ @Order(8)
+ public void testHikariDataSourceProviderWithMySQLDriver() {
+ // Set MySQL 8 driver
+ System.setProperty("store.db.driverClassName", mysql8JdbcDriver);
+
+ try {
+ // Use Hikari data source provider
+ DataSource dataSource =
EnhancedServiceLoader.load(DataSourceProvider.class, hikariDatasourceType)
+ .provide();
+ Assertions.assertNotNull(dataSource);
+
+ // Verify it's a HikariDataSource type
+ Assertions.assertTrue(dataSource instanceof
com.zaxxer.hikari.HikariDataSource);
+
+ // The most critical verification: try to get a connection (this
will trigger the actual driver loading)
+ // Note: This might throw an exception due to database connection
failure, but importantly, it should not
+ // show "Failed to load driver class" error
+ try {
+ Connection connection = dataSource.getConnection();
+ // If we reach here, it means the driver loaded successfully
and connection succeeded
+ Assertions.assertNotNull(connection);
+ connection.close();
+ } catch (SQLException e) {
+ // Database connection failure is normal (test environment
might not have real MySQL), but error message
+ // should not contain driver class loading failure
+ String errorMessage = e.getMessage();
+ Assertions.assertFalse(
+ errorMessage.contains("Failed to load driver class"),
+ "Driver class should be loaded successfully, but got:
" + errorMessage);
+ Assertions.assertFalse(
+ errorMessage.contains("HikariConfig class loader"),
+ "Driver classloader issue should be resolved, but got:
" + errorMessage);
+ // Here we expect connection-related errors, such as
connection timeout, connection refused, etc.
+ System.out.println("Expected database connection error (driver
loaded successfully): " + errorMessage);
+ }
+
+ } catch (Exception e) {
+ // If it's a driver loading related exception, the test should fail
+ if (e.getMessage().contains("Failed to load driver class")
+ || e.getMessage().contains("HikariConfig class loader")) {
+ Assertions.fail("HikariCP should load MySQL driver
successfully with custom classloader, but got: "
+ + e.getMessage());
+ }
+ // Other exceptions might be normal (such as configuration issues,
etc.)
+ System.out.println("Non-driver related exception (might be
expected): " + e.getMessage());
+ }
+ }
+
+ @Test
+ @Order(9)
+ public void testHikariDataSourceProviderWithMySQLLegacyDriver() {
+ // Test with legacy MySQL driver as well
+ System.setProperty("store.db.driverClassName", mysqlJdbcDriver);
+
+ try {
+ DataSource dataSource =
EnhancedServiceLoader.load(DataSourceProvider.class, hikariDatasourceType)
+ .provide();
+ Assertions.assertNotNull(dataSource);
+
+ // Try to get connection to verify driver loading
+ try {
+ Connection connection = dataSource.getConnection();
+ Assertions.assertNotNull(connection);
+ connection.close();
+ } catch (SQLException e) {
+ String errorMessage = e.getMessage();
+ Assertions.assertFalse(
+ errorMessage.contains("Failed to load driver class"),
+ "Legacy MySQL driver should also be loaded
successfully, but got: " + errorMessage);
+ }
+
+ } catch (Exception e) {
+ if (e.getMessage().contains("Failed to load driver class")) {
+ Assertions.fail("HikariCP should load legacy MySQL driver
successfully, but got: " + e.getMessage());
+ }
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]