From 7ad4f5f8501466c42186114522525a61f7aab457 Mon Sep 17 00:00:00 2001 From: Looly Date: Mon, 18 Dec 2023 03:27:49 +0800 Subject: [PATCH] fix code --- .../dromara/hutool/core/pool/Poolable.java | 7 + .../pool/partition/PartitionObjectPool.java | 2 +- .../pool/partition/PartitionPoolable.java | 8 +- .../core/pool/partition/PoolPartition.java | 21 +- .../hutool/db/ds/pooled/DbSetting.java | 97 --------- .../hutool/db/ds/pooled/PooledConnection.java | 75 +++---- .../hutool/db/ds/pooled/PooledDataSource.java | 201 +++++------------- .../db/ds/simple/AbstractDataSource.java | 6 +- .../hutool/db/ds/DataSourceWrapperTest.java | 4 +- .../dromara/hutool/db/{ => ds}/DsTest.java | 10 +- 10 files changed, 114 insertions(+), 317 deletions(-) delete mode 100644 hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/DbSetting.java rename hutool-db/src/test/java/org/dromara/hutool/db/{ => ds}/DsTest.java (95%) diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/pool/Poolable.java b/hutool-core/src/main/java/org/dromara/hutool/core/pool/Poolable.java index 2484f3cc4..f99d75362 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/pool/Poolable.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/pool/Poolable.java @@ -28,4 +28,11 @@ public interface Poolable extends Wrapper { * @return 最后借出时间 */ long getLastBorrow(); + + /** + * 设置最后借出时间,在成功借出此对象时更新时间 + * + * @param lastBorrow 最后借出时间 + */ + void setLastBorrow(final long lastBorrow); } 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 37eb2a4be..238b14cbd 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 @@ -113,7 +113,7 @@ public class PartitionObjectPool implements ObjectPool { * @param poolConfig 池配置 * @return 队列 */ - protected BlockingQueue> createBlockingQueue(final PartitionPoolConfig poolConfig) { + protected BlockingQueue> createBlockingQueue(final PartitionPoolConfig poolConfig) { return new ArrayBlockingQueue<>(poolConfig.getMaxSize()); } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PartitionPoolable.java b/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PartitionPoolable.java index 37eb029c5..ff620ba5a 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PartitionPoolable.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PartitionPoolable.java @@ -54,12 +54,8 @@ public class PartitionPoolable implements Poolable { return lastBorrow; } - /** - * 设置最后借出时间,在成功借出此对象时更新时间 - * - * @param lastBorrow 最后借出时间 - */ - protected void setLastBorrow(final long lastBorrow) { + @Override + public void setLastBorrow(final long lastBorrow) { this.lastBorrow = lastBorrow; } } 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 5de5617d6..faf91dbfd 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 @@ -48,7 +48,7 @@ public class PoolPartition implements ObjectPool { private final PoolConfig config; private final ObjectFactory objectFactory; - private BlockingQueue> queue; + private BlockingQueue> queue; // 记录对象总数(包括借出对象) private int total; @@ -59,7 +59,7 @@ public class PoolPartition implements ObjectPool { * @param queue 阻塞队列类型 * @param objectFactory 对象工厂,用于管理对象创建、检查和销毁 */ - public PoolPartition(final PoolConfig config, final BlockingQueue> queue, final ObjectFactory objectFactory) { + public PoolPartition(final PoolConfig config, final BlockingQueue> queue, final ObjectFactory objectFactory) { this.config = config; this.queue = queue; this.objectFactory = objectFactory; @@ -73,15 +73,15 @@ public class PoolPartition implements ObjectPool { @SuppressWarnings("resource") @Override - public PartitionPoolable borrowObject() { + public Poolable borrowObject() { // 非阻塞获取 - PartitionPoolable poolable = this.queue.poll(); + Poolable poolable = this.queue.poll(); if (null != poolable) { // 检查对象是否可用 if (this.objectFactory.validate(poolable.getRaw())) { // 检查是否超过最长空闲时间 final long maxIdle = this.config.getMaxIdle(); - if (maxIdle > 0 && (System.currentTimeMillis() - poolable.getLastBorrow()) <= maxIdle) { + if (maxIdle <= 0 || (System.currentTimeMillis() - poolable.getLastBorrow()) <= maxIdle) { poolable.setLastBorrow(System.currentTimeMillis()); return poolable; } @@ -120,7 +120,7 @@ public class PoolPartition implements ObjectPool { // 检查对象可用性 if (this.objectFactory.validate(poolable.getRaw())) { try { - this.queue.put((PartitionPoolable) poolable); + this.queue.put(poolable); } catch (final InterruptedException e) { throw new HutoolException(e); } @@ -194,7 +194,12 @@ public class PoolPartition implements ObjectPool { * * @return {@link PartitionPoolable} */ - protected PartitionPoolable createPoolable() { + @SuppressWarnings("unchecked") + protected Poolable createPoolable() { + final T t = objectFactory.create(); + if (t instanceof Poolable) { + return (Poolable) t; + } return new PartitionPoolable<>(objectFactory.create(), this); } @@ -205,7 +210,7 @@ public class PoolPartition implements ObjectPool { * @return 取出的池对象 * @throws HutoolException 中断异常 */ - private PartitionPoolable waitingPoll() throws HutoolException { + private Poolable waitingPoll() throws HutoolException { final long maxWait = this.config.getMaxWait(); try { if (maxWait <= 0) { diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/DbSetting.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/DbSetting.java deleted file mode 100644 index 2bcc0d362..000000000 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/DbSetting.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2023 looly(loolly@aliyun.com) - * Hutool is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * https://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - -package org.dromara.hutool.db.ds.pooled; - -import org.dromara.hutool.core.map.MapUtil; -import org.dromara.hutool.core.text.StrUtil; -import org.dromara.hutool.db.DbRuntimeException; -import org.dromara.hutool.db.driver.DriverUtil; -import org.dromara.hutool.db.ds.DSKeys; -import org.dromara.hutool.setting.Setting; - -/** - * 数据库配置文件类,此类对应一个数据库配置文件 - * - * @author Looly - * - */ -public class DbSetting { - /** 默认的数据库连接配置文件路径 */ - public final static String DEFAULT_DB_CONFIG_PATH = "config/db.setting"; - - private final Setting setting; - - /** - * 构造 - */ - public DbSetting() { - this(null); - } - - /** - * 构造 - * - * @param setting 数据库配置 - */ - public DbSetting(final Setting setting) { - if (null == setting) { - this.setting = new Setting(DEFAULT_DB_CONFIG_PATH); - } else { - this.setting = setting; - } - } - - /** - * 获得数据库连接信息 - * - * @param group 分组 - * @return 分组 - */ - public PooledDbConfig getDbConfig(final String group) { - final Setting config = setting.getSetting(group); - if (MapUtil.isEmpty(config)) { - throw new DbRuntimeException("No Hutool pool config for group: [{}]", group); - } - - final PooledDbConfig pooledDbConfig = new PooledDbConfig(); - - // 基本信息 - final String url = config.getAndRemove(DSKeys.KEY_ALIAS_URL); - if (StrUtil.isBlank(url)) { - throw new DbRuntimeException("No JDBC URL for group: [{}]", group); - } - pooledDbConfig.setUrl(url); - // 自动识别Driver - final String driver = config.getAndRemove(DSKeys.KEY_ALIAS_DRIVER); - pooledDbConfig.setDriver(StrUtil.isNotBlank(driver) ? driver : DriverUtil.identifyDriver(url)); - pooledDbConfig.setUser(config.getAndRemove(DSKeys.KEY_ALIAS_USER)); - pooledDbConfig.setPass(config.getAndRemove(DSKeys.KEY_ALIAS_PASSWORD)); - - // 连接池相关信息 - pooledDbConfig.setInitialSize(setting.getIntByGroup("initialSize", group, 0)); - pooledDbConfig.setMinIdle(setting.getIntByGroup("minIdle", group, 0)); - pooledDbConfig.setMaxActive(setting.getIntByGroup("maxActive", group, 8)); - pooledDbConfig.setMaxWait(setting.getLongByGroup("maxWait", group, 6000L)); - - // remarks等特殊配置,since 5.3.8 - String connValue; - for (final String key : DSKeys.KEY_CONN_PROPS) { - connValue = config.get(key); - if(StrUtil.isNotBlank(connValue)){ - pooledDbConfig.addConnProps(key, connValue); - } - } - - return pooledDbConfig; - } -} 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 8905ca399..06c54d09f 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 @@ -12,8 +12,9 @@ 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.db.DbRuntimeException; import org.dromara.hutool.setting.props.Props; import java.sql.Connection; @@ -26,21 +27,20 @@ import java.util.Properties; * * @author Looly */ -public class PooledConnection extends ConnectionWrapper { +public class PooledConnection extends ConnectionWrapper implements Poolable { - private final PooledDataSource ds; - private boolean isClosed; + private final PooledDataSource dataSource; + + private long lastBorrow = System.currentTimeMillis(); + private boolean isClosed = false; /** * 构造 * - * @param ds 数据源 - * @throws SQLException SQL异常 + * @param config 数据库配置 + * @param dataSource 数据源 */ - public PooledConnection(final PooledDataSource ds) throws SQLException { - this.ds = ds; - final PooledDbConfig config = ds.getConfig(); - + public PooledConnection(final PooledDbConfig config, final PooledDataSource dataSource) { final Props info = new Props(); final String user = config.getUser(); if (user != null) { @@ -57,56 +57,33 @@ public class PooledConnection extends ConnectionWrapper { info.putAll(connProps); } - this.raw = DriverManager.getConnection(config.getUrl(), info); + try { + this.raw = DriverManager.getConnection(config.getUrl(), info); + } catch (final SQLException e) { + throw new DbRuntimeException(e); + } + + this.dataSource = dataSource; } - /** - * 构造 - * - * @param ds {@link PooledDataSource} - * @param conn {@link Connection} - */ - public PooledConnection(final PooledDataSource ds, final Connection conn) { - this.ds = ds; - this.raw = conn; - } - - /** - * 重写关闭连接,实际操作是归还到连接池中 - */ @Override public void close() { - this.ds.free(this); this.isClosed = true; + dataSource.returnObject(this); } - /** - * 连接是否关闭,关闭条件:
- * 1、被归还到池中 - * 2、实际连接已关闭 - */ @Override - public boolean isClosed() throws SQLException { - return isClosed || raw.isClosed(); + public boolean isClosed() { + return this.isClosed; } - /** - * 打开连接 - * - * @return this - */ - protected PooledConnection open() { - this.isClosed = false; - return this; + @Override + public long getLastBorrow() { + return lastBorrow; } - /** - * 释放连接 - * - * @return this - */ - protected PooledConnection release() { - IoUtil.closeQuietly(this.raw); - return this; + @Override + public void setLastBorrow(final long lastBorrow) { + this.lastBorrow = lastBorrow; } } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledDataSource.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledDataSource.java index 0bb7aa53f..a7123e03a 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledDataSource.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledDataSource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 looly(loolly@aliyun.com) + * Copyright (c) 2023. looly(loolly@aliyun.com) * Hutool is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: @@ -12,102 +12,45 @@ package org.dromara.hutool.db.ds.pooled; -import org.dromara.hutool.core.collection.CollUtil; import org.dromara.hutool.core.io.IoUtil; -import org.dromara.hutool.core.text.StrUtil; -import org.dromara.hutool.core.thread.ThreadUtil; +import org.dromara.hutool.core.pool.ObjectFactory; +import org.dromara.hutool.core.pool.ObjectPool; +import org.dromara.hutool.core.pool.partition.PartitionObjectPool; +import org.dromara.hutool.core.pool.partition.PartitionPoolConfig; import org.dromara.hutool.db.DbRuntimeException; import org.dromara.hutool.db.ds.simple.AbstractDataSource; import java.sql.Connection; import java.sql.SQLException; -import java.util.LinkedList; -import java.util.Queue; /** - * 池化数据源 + * 池化的数据源,用于管理数据库连接 * * @author Looly - * + * @since 6.0.0 */ public class PooledDataSource extends AbstractDataSource { - private Queue freePool; - private int activeCount; // 活跃连接数 - - private final PooledDbConfig config; - - /** - * 获得一个数据源 - * - * @param group 数据源分组 - * @return {@code PooledDataSource} - */ - synchronized public static PooledDataSource getDataSource(final String group) { - return new PooledDataSource(group); - } - - /** - * 获得一个数据源,使用空分组 - * - * @return {@code PooledDataSource} - */ - synchronized public static PooledDataSource getDataSource() { - return new PooledDataSource(); - } - - // -------------------------------------------------------------------- Constructor start - /** - * 构造,读取默认的配置文件和默认分组 - */ - public PooledDataSource() { - this(StrUtil.EMPTY); - } - - /** - * 构造,读取默认的配置文件 - * - * @param group 分组 - */ - public PooledDataSource(final String group) { - this(new DbSetting(), group); - } + private final ObjectPool connPool; /** * 构造 * - * @param setting 数据库配置文件对象 - * @param group 分组 - */ - public PooledDataSource(final DbSetting setting, final String group) { - this(setting.getDbConfig(group)); - } - - /** - * 构造 - * - * @param config 数据库配置 + * @param config 数据库池配置 */ public PooledDataSource(final PooledDbConfig config) { - this.config = config; - freePool = new LinkedList<>(); - int initialSize = config.getInitialSize(); - try { - while (initialSize-- > 0) { - freePool.offer(newConnection()); - } - } catch (final SQLException e) { - throw new DbRuntimeException(e); - } - } - // -------------------------------------------------------------------- Constructor start + final PartitionPoolConfig poolConfig = (PartitionPoolConfig) PartitionPoolConfig.of() + .setPartitionSize(1) + .setMaxWait(config.getMaxWait()) + .setMinSize(config.getInitialSize()) + .setMaxSize(config.getMaxActive()); + + this.connPool = new PartitionObjectPool<>(poolConfig, createConnFactory(config)); + } - /** - * 从数据库连接池中获取数据库连接对象 - */ @Override - public synchronized Connection getConnection() throws SQLException { - return getConnection(config.getMaxWait()); + public Connection getConnection() throws SQLException { + return (Connection) connPool.borrowObject(); } @Override @@ -115,84 +58,46 @@ public class PooledDataSource extends AbstractDataSource { throw new SQLException("Pooled DataSource is not allow to get special Connection!"); } - /** - * 释放连接,连接会被返回给连接池 - * - * @param conn 连接 - * @return 释放成功与否 - */ - protected synchronized boolean free(final PooledConnection conn) { - activeCount--; - return freePool.offer(conn); - } - - /** - * 创建新连接 - * - * @return 新连接 - * @throws SQLException SQL异常 - */ - public PooledConnection newConnection() throws SQLException { - return new PooledConnection(this); - } - - public PooledDbConfig getConfig() { - return config; - } - - /** - * 获取连接对象 - * - * @param wait 当池中无连接等待的毫秒数 - * @return 连接对象 - * @throws SQLException SQL异常 - */ - public PooledConnection getConnection(final long wait) throws SQLException { - try { - return getConnectionDirect(); - } catch (final Exception e) { - ThreadUtil.sleep(wait); - } - return getConnectionDirect(); - } - @Override - synchronized public void close() { - if (CollUtil.isNotEmpty(this.freePool)) { - this.freePool.forEach(PooledConnection::release); - this.freePool.clear(); - this.freePool = null; - } - } - - @Override - protected void finalize() { - IoUtil.closeQuietly(this); + public void close() { + IoUtil.closeQuietly(this.connPool); } /** - * 直接从连接池中获取连接,如果池中无连接直接抛出异常 + * 将连接返回到池中 * - * @return PooledConnection - * @throws SQLException SQL异常 + * @param conn {@link PooledConnection} */ - private PooledConnection getConnectionDirect() throws SQLException { - if (null == freePool) { - throw new SQLException("PooledDataSource is closed!"); - } - - final int maxActive = config.getMaxActive(); - if (maxActive <= 0 || maxActive < this.activeCount) { - // 超过最大使用限制 - throw new SQLException("In used Connection is more than Max Active."); - } - - PooledConnection conn = freePool.poll(); - if (null == conn || conn.open().isClosed()) { - conn = this.newConnection(); - } - activeCount++; - return conn; + public void returnObject(final PooledConnection conn) { + this.connPool.returnObject(conn); } + /** + * 创建自定义的{@link PooledConnection}工厂类 + * + * @param config 数据库配置 + * @return {@link ObjectFactory} + */ + private ObjectFactory createConnFactory(final PooledDbConfig config) { + return new ObjectFactory() { + @Override + public Connection create() { + return new PooledConnection(config, PooledDataSource.this); + } + + @Override + public boolean validate(final Connection connection) { + try { + return null != connection && connection.isValid((int) config.getMaxWait()); + } catch (final SQLException e) { + throw new DbRuntimeException(e); + } + } + + @Override + public void destroy(final Connection connection) { + IoUtil.closeQuietly(connection); + } + }; + } } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/AbstractDataSource.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/AbstractDataSource.java index fae0e20a0..f9c4245d8 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/AbstractDataSource.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/AbstractDataSource.java @@ -24,10 +24,11 @@ import java.util.logging.Logger; /** * 数据源抽象实现 - * @author Looly * + * @author Looly */ -public abstract class AbstractDataSource implements DataSource, Cloneable, Closeable{ +public abstract class AbstractDataSource implements DataSource, Cloneable, Closeable { + @Override public PrintWriter getLogWriter() { return DriverManager.getLogWriter(); @@ -60,6 +61,7 @@ public abstract class AbstractDataSource implements DataSource, Cloneable, Close /** * Support from JDK7 + * * @since 1.7 */ @Override diff --git a/hutool-db/src/test/java/org/dromara/hutool/db/ds/DataSourceWrapperTest.java b/hutool-db/src/test/java/org/dromara/hutool/db/ds/DataSourceWrapperTest.java index 7262a444a..edd2c0c9e 100644 --- a/hutool-db/src/test/java/org/dromara/hutool/db/ds/DataSourceWrapperTest.java +++ b/hutool-db/src/test/java/org/dromara/hutool/db/ds/DataSourceWrapperTest.java @@ -12,6 +12,7 @@ package org.dromara.hutool.db.ds; +import org.dromara.hutool.db.ds.simple.DbConfig; import org.dromara.hutool.db.ds.simple.SimpleDataSource; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -20,7 +21,8 @@ public class DataSourceWrapperTest { @Test public void cloneTest(){ - final SimpleDataSource simpleDataSource = new SimpleDataSource("jdbc:sqlite:test.db", "", ""); + final SimpleDataSource simpleDataSource = new SimpleDataSource( + new DbConfig("jdbc:sqlite:test.db", "", "")); final DSWrapper wrapper = new DSWrapper(simpleDataSource, "test.driver"); final DSWrapper clone = wrapper.clone(); diff --git a/hutool-db/src/test/java/org/dromara/hutool/db/DsTest.java b/hutool-db/src/test/java/org/dromara/hutool/db/ds/DsTest.java similarity index 95% rename from hutool-db/src/test/java/org/dromara/hutool/db/DsTest.java rename to hutool-db/src/test/java/org/dromara/hutool/db/ds/DsTest.java index 6b9c751d6..a41de92c9 100644 --- a/hutool-db/src/test/java/org/dromara/hutool/db/DsTest.java +++ b/hutool-db/src/test/java/org/dromara/hutool/db/ds/DsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 looly(loolly@aliyun.com) + * Copyright (c) 2023. looly(loolly@aliyun.com) * Hutool is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: @@ -10,11 +10,12 @@ * See the Mulan PSL v2 for more details. */ -package org.dromara.hutool.db; +package org.dromara.hutool.db.ds; +import com.mchange.v2.c3p0.ComboPooledDataSource; import org.dromara.hutool.core.collection.CollUtil; -import org.dromara.hutool.db.ds.DSUtil; -import org.dromara.hutool.db.ds.DSWrapper; +import org.dromara.hutool.db.Db; +import org.dromara.hutool.db.Entity; import org.dromara.hutool.db.ds.bee.BeeDSFactory; import org.dromara.hutool.db.ds.c3p0.C3p0DSFactory; import org.dromara.hutool.db.ds.dbcp.DbcpDSFactory; @@ -22,7 +23,6 @@ import org.dromara.hutool.db.ds.druid.DruidDSFactory; import org.dromara.hutool.db.ds.hikari.HikariDSFactory; import org.dromara.hutool.db.ds.pooled.PooledDSFactory; import org.dromara.hutool.db.ds.tomcat.TomcatDSFactory; -import com.mchange.v2.c3p0.ComboPooledDataSource; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test;