From cbaf8103e95d319ddecd2a42bd93833509c03b10 Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 12 Nov 2024 13:40:07 +0800 Subject: [PATCH] fix pool bug --- .../pool/partition/PartitionObjectPool.java | 7 ++++ .../core/pool/partition/PoolPartition.java | 6 +--- .../java/org/dromara/hutool/db/ds/DSPool.java | 9 +++++ .../java/org/dromara/hutool/db/ds/DSUtil.java | 1 + .../hutool/db/ds/pooled/PooledConnection.java | 34 +++++++++---------- .../hutool/db/ds/pooled/PooledDataSource.java | 20 ++++++----- .../hutool/db/ds/PooledDataSourceTest.java | 30 ++++++++++++++++ 7 files changed, 76 insertions(+), 31 deletions(-) create mode 100644 hutool-db/src/test/java/org/dromara/hutool/db/ds/PooledDataSourceTest.java diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PartitionObjectPool.java b/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PartitionObjectPool.java index 91f0f4f98..1d31146c9 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PartitionObjectPool.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PartitionObjectPool.java @@ -20,6 +20,7 @@ import org.dromara.hutool.core.io.IoUtil; import org.dromara.hutool.core.pool.ObjectFactory; import org.dromara.hutool.core.pool.ObjectPool; import org.dromara.hutool.core.pool.Poolable; +import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.thread.ThreadUtil; import java.io.IOException; @@ -117,6 +118,12 @@ public class PartitionObjectPool implements ObjectPool { IoUtil.closeQuietly(this.partitions); } + @Override + public String toString() { + return StrUtil.format("PartitionObjectPool: total: {}, idle: {}, active: {}", + getTotal(), getIdleCount(), getActiveCount()); + } + /** * 创建阻塞队列,默认为{@link ArrayBlockingQueue}
* 如果需要自定义队列类型,子类重写此方法 diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PoolPartition.java b/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PoolPartition.java index f64738a44..94c705972 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PoolPartition.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PoolPartition.java @@ -81,7 +81,7 @@ public class PoolPartition implements ObjectPool { // 检查是否超过最长空闲时间 final long maxIdle = this.config.getMaxIdle(); if (maxIdle <= 0 || poolable.getIdle() <= maxIdle) { - return poolable.getRaw(); + return obj; } } @@ -188,11 +188,7 @@ public class PoolPartition implements ObjectPool { return wrapPoolable(t); } - @SuppressWarnings("unchecked") private Poolable wrapPoolable(final T t) { - if (t instanceof Poolable) { - return (Poolable) t; - } return new PartitionPoolable<>(t, this); } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSPool.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSPool.java index 1e09ace41..f8c16db42 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSPool.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSPool.java @@ -105,6 +105,15 @@ public class DSPool implements Closeable { return this.factory.getDataSourceName(); } + /** + * 获取数据源工厂 + * + * @return 数据源工厂 + */ + public DSFactory getFactory() { + return this.factory; + } + /** * 设置自定义的{@link DSFactory} * diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSUtil.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSUtil.java index 802e78f28..72d6c7019 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSUtil.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSUtil.java @@ -120,6 +120,7 @@ public class DSUtil { * @param dsFactory 数据源工厂 * @return 自定义的数据源工厂 */ + @SuppressWarnings("resource") public static DSFactory setGlobalDSFactory(final DSFactory dsFactory) { DSPool.getInstance().setFactory(dsFactory); return dsFactory; diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledConnection.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledConnection.java index 1fe4519f7..4709d64dd 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledConnection.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledConnection.java @@ -16,14 +16,13 @@ package org.dromara.hutool.db.ds.pooled; +import org.dromara.hutool.core.io.IoUtil; import org.dromara.hutool.core.map.MapUtil; -import org.dromara.hutool.core.pool.Poolable; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.db.DbException; import org.dromara.hutool.db.config.ConnectionConfig; import org.dromara.hutool.setting.props.Props; -import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; @@ -33,23 +32,21 @@ import java.util.Properties; * * @author Looly */ -public class PooledConnection extends ConnectionWrapper implements Poolable { +public class PooledConnection extends ConnectionWrapper { private final PooledDataSource dataSource; - - private long lastBorrow = System.currentTimeMillis(); private boolean isClosed = false; /** * 构造 * - * @param config 数据库配置 + * @param config 数据库配置 * @param dataSource 数据源 */ public PooledConnection(final ConnectionConfig config, final PooledDataSource dataSource) { // issue#IA6EUQ 部分驱动无法自动加载,此处手动完成 final String driver = config.getDriver(); - if(StrUtil.isNotBlank(driver)){ + if (StrUtil.isNotBlank(driver)) { try { Class.forName(driver); } catch (final ClassNotFoundException e) { @@ -74,9 +71,9 @@ public class PooledConnection extends ConnectionWrapper implements Poolable + * 关闭操作在池中的意义为使用完毕,归还到池中
+ * 如果想彻底关闭连接,请使用{@link #destroy()}方法 + */ @Override public void close() { this.isClosed = true; @@ -97,13 +99,11 @@ public class PooledConnection extends ConnectionWrapper implements Poolable connPool; + private final ObjectPool connPool; /** * 构造 @@ -83,8 +83,8 @@ public class PooledDataSource extends AbstractDataSource { } @Override - public Connection getConnection() throws SQLException { - return (Connection) connPool.borrowObject(); + public PooledConnection getConnection() throws SQLException { + return connPool.borrowObject(); } @Override @@ -112,15 +112,15 @@ public class PooledDataSource extends AbstractDataSource { * @param config 数据库配置 * @return {@link ObjectFactory} */ - private ObjectFactory createConnFactory(final ConnectionConfig config) { - return new ObjectFactory() { + private ObjectFactory createConnFactory(final ConnectionConfig config) { + return new ObjectFactory() { @Override - public Connection create() { + public PooledConnection create() { return new PooledConnection(config, PooledDataSource.this); } @Override - public boolean validate(final Connection connection) { + public boolean validate(final PooledConnection connection) { try { return null != connection && connection.isValid(maxWait); @@ -133,8 +133,10 @@ public class PooledDataSource extends AbstractDataSource { } @Override - public void destroy(final Connection connection) { - IoUtil.closeQuietly(connection); + public void destroy(final PooledConnection connection) { + if(null != connection){ + connection.destroy(); + } } }; } diff --git a/hutool-db/src/test/java/org/dromara/hutool/db/ds/PooledDataSourceTest.java b/hutool-db/src/test/java/org/dromara/hutool/db/ds/PooledDataSourceTest.java new file mode 100644 index 000000000..874afdf87 --- /dev/null +++ b/hutool-db/src/test/java/org/dromara/hutool/db/ds/PooledDataSourceTest.java @@ -0,0 +1,30 @@ +package org.dromara.hutool.db.ds; + +import org.dromara.hutool.db.DbException; +import org.dromara.hutool.db.config.SettingConfigParser; +import org.dromara.hutool.db.ds.pooled.PooledDSFactory; +import org.dromara.hutool.setting.Setting; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.sql.SQLException; + +public class PooledDataSourceTest { + @Test + void getConnTest() { + final DSPool dsPool = new DSPool( + new SettingConfigParser(new Setting("config/db.setting")), + new PooledDSFactory()); + + final DSWrapper test = dsPool.getDataSource("test"); + Assertions.assertEquals("org.dromara.hutool.db.ds.pooled.PooledDataSource", test.getRaw().getClass().getName()); + for (int i = 0; i < 1000; i++) { + try { + test.getConnection().close(); + } catch (final SQLException e) { + throw new DbException(e); + } + } + + } +}