This commit is contained in:
Looly 2023-03-27 01:47:02 +08:00
parent 7324502249
commit 16f7549c7d
27 changed files with 454 additions and 393 deletions

View File

@ -890,7 +890,7 @@ public class IoUtil extends NioUtil {
* *
* @param closeable 被关闭的对象 * @param closeable 被关闭的对象
*/ */
public static void close(final Closeable closeable) { public static void close(final AutoCloseable closeable) {
if (null != closeable) { if (null != closeable) {
try { try {
closeable.close(); closeable.close();

View File

@ -2,7 +2,7 @@ package cn.hutool.db;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.db.ds.DSFactory; import cn.hutool.db.ds.DSUtil;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.util.Arrays; import java.util.Arrays;
@ -31,7 +31,7 @@ public class DaoTemplate {
*/ */
protected Db db; protected Db db;
//--------------------------------------------------------------- Constructor start // region ----- Constructor
/** /**
* 构造此构造需要自定义SqlRunner主键默认为id * 构造此构造需要自定义SqlRunner主键默认为id
@ -49,7 +49,7 @@ public class DaoTemplate {
* @param primaryKeyField 主键字段名 * @param primaryKeyField 主键字段名
*/ */
public DaoTemplate(final String tableName, final String primaryKeyField) { public DaoTemplate(final String tableName, final String primaryKeyField) {
this(tableName, primaryKeyField, DSFactory.get()); this(tableName, primaryKeyField, DSUtil.getDS());
} }
/** /**
@ -87,9 +87,9 @@ public class DaoTemplate {
} }
this.db = db; this.db = db;
} }
//--------------------------------------------------------------- Constructor end // endregion
//------------------------------------------------------------- Add start // region ----- Add
/** /**
* 添加 * 添加
@ -123,9 +123,9 @@ public class DaoTemplate {
public Long addForGeneratedKey(final Entity entity) throws DbRuntimeException { public Long addForGeneratedKey(final Entity entity) throws DbRuntimeException {
return db.insertForGeneratedKey(fixEntity(entity)); return db.insertForGeneratedKey(fixEntity(entity));
} }
//------------------------------------------------------------- Add end // endregion
//------------------------------------------------------------- Delete start // region ----- Delete
/** /**
* 删除 * 删除
@ -172,9 +172,9 @@ public class DaoTemplate {
} }
return db.del(fixEntity(where)); return db.del(fixEntity(where));
} }
//------------------------------------------------------------- Delete end // endregion
//------------------------------------------------------------- Update start // region ----- Update
/** /**
* 按照条件更新 * 按照条件更新
@ -225,10 +225,9 @@ public class DaoTemplate {
public int addOrUpdate(final Entity entity) throws DbRuntimeException { public int addOrUpdate(final Entity entity) throws DbRuntimeException {
return null == entity.get(primaryKeyField) ? add(entity) : update(entity); return null == entity.get(primaryKeyField) ? add(entity) : update(entity);
} }
//------------------------------------------------------------- Update end // endregion
//------------------------------------------------------------- Get start
//region ----- Get
/** /**
* 根据主键获取单个记录 * 根据主键获取单个记录
* *
@ -265,9 +264,9 @@ public class DaoTemplate {
public Entity get(final Entity where) throws DbRuntimeException { public Entity get(final Entity where) throws DbRuntimeException {
return db.get(fixEntity(where)); return db.get(fixEntity(where));
} }
//------------------------------------------------------------- Get end // endregion
//------------------------------------------------------------- Find start // region ----- Find and page
/** /**
* 根据某个字段值查询结果 * 根据某个字段值查询结果
@ -367,7 +366,7 @@ public class DaoTemplate {
public boolean exist(final Entity where) throws DbRuntimeException { public boolean exist(final Entity where) throws DbRuntimeException {
return this.count(where) > 0; return this.count(where) > 0;
} }
//------------------------------------------------------------- Find end // endregion
/** /**
* 修正Entity对象避免null和填充表名 * 修正Entity对象避免null和填充表名

View File

@ -3,7 +3,7 @@ package cn.hutool.db;
import cn.hutool.core.lang.func.SerConsumer; import cn.hutool.core.lang.func.SerConsumer;
import cn.hutool.db.dialect.Dialect; import cn.hutool.db.dialect.Dialect;
import cn.hutool.db.dialect.DialectFactory; import cn.hutool.db.dialect.DialectFactory;
import cn.hutool.db.ds.DSFactory; import cn.hutool.db.ds.DSUtil;
import cn.hutool.db.transaction.TransactionLevel; import cn.hutool.db.transaction.TransactionLevel;
import cn.hutool.log.StaticLog; import cn.hutool.log.StaticLog;
@ -28,7 +28,7 @@ public class Db extends AbstractDb<Db> {
* @return Db * @return Db
*/ */
public static Db of() { public static Db of() {
return of(DSFactory.get()); return of(DSUtil.getDS());
} }
/** /**
@ -39,7 +39,7 @@ public class Db extends AbstractDb<Db> {
* @return Db * @return Db
*/ */
public static Db of(final String group) { public static Db of(final String group) {
return of(DSFactory.get(group)); return of(DSUtil.getDS(group));
} }
/** /**

View File

@ -2,16 +2,11 @@ package cn.hutool.db;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.IoUtil;
import cn.hutool.db.ds.DSFactory;
import cn.hutool.db.sql.SqlLog; import cn.hutool.db.sql.SqlLog;
import cn.hutool.log.Log; import cn.hutool.log.Log;
import cn.hutool.log.level.Level; import cn.hutool.log.level.Level;
import cn.hutool.setting.Setting; import cn.hutool.setting.Setting;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
/** /**
* 数据库操作工具类 * 数据库操作工具类
* *
@ -38,54 +33,6 @@ public final class DbUtil {
} }
} }
/**
* 获得默认数据源
*
* @return 默认数据源
*/
public static DataSource getDs() {
return DSFactory.get();
}
/**
* 获取指定分组的数据源
*
* @param group 分组
* @return 数据源
*/
public static DataSource getDs(final String group) {
return DSFactory.get(group);
}
/**
* 获得JNDI数据源
*
* @param jndiName JNDI名称
* @return 数据源
*/
public static DataSource getJndiDsWithLog(final String jndiName) {
try {
return getJndiDs(jndiName);
} catch (final DbRuntimeException e) {
log.error(e.getCause(), "Find JNDI datasource error!");
}
return null;
}
/**
* 获得JNDI数据源
*
* @param jndiName JNDI名称
* @return 数据源
*/
public static DataSource getJndiDs(final String jndiName) {
try {
return (DataSource) new InitialContext().lookup(jndiName);
} catch (final NamingException e) {
throw new DbRuntimeException(e);
}
}
/** /**
* 移除配置文件中的Show SQL相关配置项<br> * 移除配置文件中的Show SQL相关配置项<br>
* 此方法用于移除用户配置在分组下的配置项目 * 此方法用于移除用户配置在分组下的配置项目

View File

@ -4,7 +4,7 @@ import cn.hutool.core.lang.func.SerConsumer;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.db.dialect.Dialect; import cn.hutool.db.dialect.Dialect;
import cn.hutool.db.dialect.DialectFactory; import cn.hutool.db.dialect.DialectFactory;
import cn.hutool.db.ds.DSFactory; import cn.hutool.db.ds.DSUtil;
import cn.hutool.log.Log; import cn.hutool.log.Log;
import cn.hutool.log.LogFactory; import cn.hutool.log.LogFactory;
@ -34,7 +34,7 @@ public class Session extends AbstractDb<Session> implements Closeable {
* @since 3.2.3 * @since 3.2.3
*/ */
public static Session of() { public static Session of() {
return new Session(DSFactory.get()); return new Session(DSUtil.getDS());
} }
/** /**
@ -45,7 +45,7 @@ public class Session extends AbstractDb<Session> implements Closeable {
* @since 4.0.11 * @since 4.0.11
*/ */
public static Session of(final String group) { public static Session of(final String group) {
return new Session(DSFactory.get(group)); return new Session(DSUtil.getDS(group));
} }
/** /**

View File

@ -9,7 +9,7 @@ import javax.sql.DataSource;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.db.DbRuntimeException; import cn.hutool.db.DbRuntimeException;
import cn.hutool.db.DbUtil; import cn.hutool.db.DbUtil;
import cn.hutool.db.ds.DataSourceWrapper; import cn.hutool.db.ds.DSWrapper;
/** /**
* 驱动相关工具类包括自动获取驱动类名 * 驱动相关工具类包括自动获取驱动类名
@ -36,8 +36,8 @@ public class DriverUtil {
* @return 驱动 * @return 驱动
*/ */
public static String identifyDriver(final DataSource ds) { public static String identifyDriver(final DataSource ds) {
if(ds instanceof DataSourceWrapper) { if(ds instanceof DSWrapper) {
final String driver = ((DataSourceWrapper)ds).getDriver(); final String driver = ((DSWrapper)ds).getDriver();
if(StrUtil.isNotBlank(driver)) { if(StrUtil.isNotBlank(driver)) {
return driver; return driver;
} }

View File

@ -21,9 +21,13 @@ import java.util.Map;
* *
* @author looly * @author looly
*/ */
public abstract class AbstractDSFactory extends DSFactory { public abstract class AbstractDSFactory implements DSFactory {
private static final long serialVersionUID = -6407302276272379881L; private static final long serialVersionUID = -6407302276272379881L;
/**
* 数据源名
*/
protected final String dataSourceName;
/** /**
* 数据库连接配置文件 * 数据库连接配置文件
*/ */
@ -31,7 +35,7 @@ public abstract class AbstractDSFactory extends DSFactory {
/** /**
* 数据源池 * 数据源池
*/ */
private final Map<String, DataSourceWrapper> dsMap; private final Map<String, DSWrapper> dsMap;
/** /**
* 构造 * 构造
@ -42,18 +46,18 @@ public abstract class AbstractDSFactory extends DSFactory {
* @param setting 数据库连接配置如果为{@code null}则读取全局自定义或默认配置 * @param setting 数据库连接配置如果为{@code null}则读取全局自定义或默认配置
*/ */
public AbstractDSFactory(final String dataSourceName, final Class<? extends DataSource> dataSourceClass, Setting setting) { public AbstractDSFactory(final String dataSourceName, final Class<? extends DataSource> dataSourceClass, Setting setting) {
super(dataSourceName);
//此参数的作用是在detectDSFactory方法自动检测所用连接池时如果实现类不存在调用此方法会自动抛出异常从而切换到下一种连接池的检测 //此参数的作用是在detectDSFactory方法自动检测所用连接池时如果实现类不存在调用此方法会自动抛出异常从而切换到下一种连接池的检测
Assert.notNull(dataSourceClass); Assert.notNull(dataSourceClass);
this.dataSourceName = dataSourceName;
if (null == setting) { if (null == setting) {
setting = GlobalDbConfig.createDbSetting(); setting = GlobalDbConfig.createDbSetting();
} }
// 读取配置用于SQL打印 // 读取配置用于SQL打印
DbUtil.setShowSqlGlobal(setting); DbUtil.setShowSqlGlobal(setting);
this.setting = setting; this.setting = setting;
this.dsMap = new SafeConcurrentHashMap<>(); this.dsMap = new SafeConcurrentHashMap<>();
} }
@ -68,91 +72,38 @@ public abstract class AbstractDSFactory extends DSFactory {
} }
@Override @Override
synchronized public DataSource getDataSource(String group) { public String getDataSourceName() {
return this.dataSourceName;
}
@Override
public DataSource getDataSource(String group) {
if (group == null) { if (group == null) {
group = StrUtil.EMPTY; group = StrUtil.EMPTY;
} }
// 如果已经存在已有数据源连接池直接返回 // 如果已经存在已有数据源连接池直接返回
final DataSourceWrapper existedDataSource = dsMap.get(group); return dsMap.computeIfAbsent(group, this::_createDataSource);
if (existedDataSource != null) {
return existedDataSource;
}
final DataSourceWrapper ds = createDataSource(group);
// 添加到数据源池中以备下次使用
dsMap.put(group, ds);
return ds;
} }
/**
* 创建数据源
*
* @param group 分组
* @return {@link DataSourceWrapper} 数据源包装
*/
private DataSourceWrapper createDataSource(String group) {
if (group == null) {
group = StrUtil.EMPTY;
}
final Setting config = setting.getSetting(group);
if (MapUtil.isEmpty(config)) {
throw new DbRuntimeException("No config for group: [{}]", group);
}
// 基本信息
final String url = config.getAndRemove(KEY_ALIAS_URL);
if (StrUtil.isBlank(url)) {
throw new DbRuntimeException("No JDBC URL for group: [{}]", group);
}
// 移除用户可能误加入的show sql配置项
// issue#I3VW0R@Gitee
DbUtil.removeShowSqlParams(config);
// 自动识别Driver
String driver = config.getAndRemove(KEY_ALIAS_DRIVER);
if (StrUtil.isBlank(driver)) {
driver = DriverUtil.identifyDriver(url);
}
final String user = config.getAndRemove(KEY_ALIAS_USER);
final String pass = config.getAndRemove(KEY_ALIAS_PASSWORD);
return DataSourceWrapper.wrap(createDataSource(url, driver, user, pass, config), driver);
}
/**
* 创建新的{@link DataSource}<br>
*
* @param jdbcUrl JDBC连接字符串
* @param driver 数据库驱动类名
* @param user 用户名
* @param pass 密码
* @param poolSetting 分组下的连接池配置文件
* @return {@link DataSource}
*/
protected abstract DataSource createDataSource(String jdbcUrl, String driver, String user, String pass, Setting poolSetting);
@Override @Override
public void close(String group) { synchronized public void closeDataSource(String group) {
if (group == null) { if (group == null) {
group = StrUtil.EMPTY; group = StrUtil.EMPTY;
} }
final DataSourceWrapper ds = dsMap.get(group); final DSWrapper ds = dsMap.get(group);
if (ds != null) { if (ds != null) {
ds.close(); ds.close();
//noinspection resource
dsMap.remove(group); dsMap.remove(group);
} }
} }
@Override @Override
public void destroy() { public void close() {
if (MapUtil.isNotEmpty(dsMap)) { if (MapUtil.isNotEmpty(dsMap)) {
final Collection<DataSourceWrapper> values = dsMap.values(); final Collection<DSWrapper> values = dsMap.values();
for (final DataSourceWrapper ds : values) { for (final DSWrapper ds : values) {
ds.close(); ds.close();
} }
dsMap.clear(); dsMap.clear();
@ -193,4 +144,54 @@ public abstract class AbstractDSFactory extends DSFactory {
return setting.equals(other.setting); return setting.equals(other.setting);
} }
} }
/**
* 创建新的{@link DataSource}<br>
* 子类通过实现此方法创建一个对接连接池的数据源
*
* @param jdbcUrl JDBC连接字符串
* @param driver 数据库驱动类名
* @param user 用户名
* @param pass 密码
* @param poolSetting 分组下的连接池配置文件
* @return {@link DataSource}
*/
protected abstract DataSource createDataSource(String jdbcUrl, String driver, String user, String pass, Setting poolSetting);
/**
* 创建数据源对于不同连接池名称的的差异做兼容如用户配置user和username都表示用户名
*
* @param group 分组
* @return {@link DSWrapper} 数据源包装
*/
private DSWrapper _createDataSource(String group) {
if (group == null) {
group = StrUtil.EMPTY;
}
final Setting config = setting.getSetting(group);
if (MapUtil.isEmpty(config)) {
throw new DbRuntimeException("No config for group: [{}]", group);
}
// 基本信息
final String url = config.getAndRemove(DSKeys.KEY_ALIAS_URL);
if (StrUtil.isBlank(url)) {
throw new DbRuntimeException("No JDBC URL for group: [{}]", group);
}
// 移除用户可能误加入的show sql配置项
// issue#I3VW0R@Gitee
DbUtil.removeShowSqlParams(config);
// 自动识别Driver
String driver = config.getAndRemove(DSKeys.KEY_ALIAS_DRIVER);
if (StrUtil.isBlank(driver)) {
driver = DriverUtil.identifyDriver(url);
}
final String user = config.getAndRemove(DSKeys.KEY_ALIAS_USER);
final String pass = config.getAndRemove(DSKeys.KEY_ALIAS_PASSWORD);
return DSWrapper.wrap(createDataSource(url, driver, user, pass, config), driver);
}
} }

View File

@ -1,15 +1,6 @@
package cn.hutool.db.ds; package cn.hutool.db.ds;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.db.ds.bee.BeeDSFactory;
import cn.hutool.db.ds.c3p0.C3p0DSFactory;
import cn.hutool.db.ds.dbcp.DbcpDSFactory;
import cn.hutool.db.ds.druid.DruidDSFactory;
import cn.hutool.db.ds.hikari.HikariDSFactory;
import cn.hutool.db.ds.pooled.PooledDSFactory;
import cn.hutool.db.ds.tomcat.TomcatDSFactory;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import cn.hutool.setting.Setting; import cn.hutool.setting.Setting;
import javax.sql.DataSource; import javax.sql.DataSource;
@ -17,48 +8,40 @@ import java.io.Closeable;
import java.io.Serializable; import java.io.Serializable;
/** /**
* 抽象数据源工厂类<br> * 多数据源工厂方法接口借助不同配置同一个工厂可以连接多个相同或不同的数据库但是连接池只能使用一种<br>
* 通过实现{@link #getDataSource(String)} 方法实现数据源的获取<br> * 通过实现{@link #getDataSource(String)} 方法完成数据源的获取<br>
* 如果{@link DataSource} 的实现是数据库连接池库应该在getDataSource调用时创建数据源并缓存 * 如果{@link DataSource} 的实现是数据库连接池库应该在getDataSource调用时创建数据源并缓存关系如下
* <pre>
* DSFactory
* _____________________|____________________
* | | | |
* HikariDSFactory DruidDSFactory XXXDSFactory ...
* _____|____ | _____|____
* | | | | |
* MySQL SQLite SQLServer XXXDB XXXDB2
* </pre>
*
* <p>
* 工厂创建请使用{@link DSUtil#createFactory(Setting)}
* </p>
* *
* @author Looly * @author Looly
*
*/ */
public abstract class DSFactory implements Closeable, Serializable{ public interface DSFactory extends Closeable, Serializable {
private static final long serialVersionUID = -8789780234095234765L;
private static final Log log = LogFactory.get();
/** 某些数据库需要的特殊配置项需要的配置项 */
public static final String[] KEY_CONN_PROPS = {"remarks", "useInformationSchema"};
/** 别名字段名URL */
public static final String[] KEY_ALIAS_URL = { "url", "jdbcUrl" };
/** 别名字段名:驱动名 */
public static final String[] KEY_ALIAS_DRIVER = { "driver", "driverClassName" };
/** 别名字段名:用户名 */
public static final String[] KEY_ALIAS_USER = { "user", "username" };
/** 别名字段名:密码 */
public static final String[] KEY_ALIAS_PASSWORD = { "pass", "password" };
/** 数据源名 */
protected final String dataSourceName;
/** /**
* 构造 * 获取自定义的数据源名称用于识别连接池
* *
* @param dataSourceName 数据源名称 * @return 自定义的数据源名称
*/ */
public DSFactory(final String dataSourceName) { String getDataSourceName();
this.dataSourceName = dataSourceName;
}
/** /**
* 获得默认数据源 * 获得默认数据源""分组的数据源
* *
* @return 数据源 * @return 数据源
*/ */
public DataSource getDataSource() { default DataSource getDataSource() {
return getDataSource(StrUtil.EMPTY); return getDataSource(StrUtil.EMPTY);
} }
@ -68,123 +51,19 @@ public abstract class DSFactory implements Closeable, Serializable{
* @param group 分组名 * @param group 分组名
* @return 数据源 * @return 数据源
*/ */
public abstract DataSource getDataSource(String group); DataSource getDataSource(String group);
/** /**
* 关闭默认数据源空组 * 关闭默认数据源空组
*/ */
@Override default void closeDataSource() {
public void close() { closeDataSource(StrUtil.EMPTY);
close(StrUtil.EMPTY);
} }
/** /**
* 关闭对应数据源 * 关闭(归还)对应数据源
* *
* @param group 分组 * @param group 分组
*/ */
public abstract void close(String group); void closeDataSource(String group);
/**
* 销毁工厂类关闭所有数据源
*/
public abstract void destroy();
// ------------------------------------------------------------------------- Static start
/**
* 获得数据源<br>
* 使用默认配置文件的无分组配置
*
* @return 数据源
*/
public static DataSource get() {
return get(null);
}
/**
* 获得数据源
*
* @param group 配置文件中对应的分组
* @return 数据源
*/
public static DataSource get(final String group) {
return GlobalDSFactory.get().getDataSource(group);
}
/**
* 设置全局的数据源工厂<br>
* 在项目中存在多个连接池库的情况下我们希望使用低优先级的库时使用此方法自定义之<br>
* 重新定义全局的数据源工厂此方法可在以下两种情况下调用
*
* <pre>
* 1. 在get方法调用前调用此方法来自定义全局的数据源工厂
* 2. 替换已存在的全局数据源工厂当已存在时会自动关闭
* </pre>
*
* @param dsFactory 数据源工厂
* @return 自定义的数据源工厂
*/
public static DSFactory setCurrentDSFactory(final DSFactory dsFactory) {
return GlobalDSFactory.set(dsFactory);
}
/**
* 创建数据源实现工厂<br>
* 此方法通过试错方式查找引入项目的连接池库按照优先级寻找一旦寻找到则创建对应的数据源工厂<br>
* 连接池优先级Hikari &gt; Druid &gt; Tomcat &gt; Dbcp &gt; C3p0 &gt; Hutool Pooled
*
* @param setting 数据库配置项
* @return 日志实现类
*/
public static DSFactory of(final Setting setting) {
final DSFactory dsFactory = doCreate(setting);
log.debug("Use [{}] DataSource As Default", dsFactory.dataSourceName);
return dsFactory;
}
/**
* 创建数据源实现工厂<br>
* 此方法通过试错方式查找引入项目的连接池库按照优先级寻找一旦寻找到则创建对应的数据源工厂<br>
* 连接池优先级Hikari &gt; Druid &gt; Tomcat &gt; BeeCP &gt; Dbcp &gt; C3p0 &gt; Hutool Pooled
*
* @param setting 数据库配置项
* @return 日志实现类
* @since 4.1.3
*/
private static DSFactory doCreate(final Setting setting) {
try {
return new HikariDSFactory(setting);
} catch (final NoClassDefFoundError | NoSuchMethodError e) {
// ignore
}
try {
return new DruidDSFactory(setting);
} catch (final NoClassDefFoundError | NoSuchMethodError e) {
// ignore
}
try {
return new TomcatDSFactory(setting);
} catch (final NoClassDefFoundError | NoSuchMethodError e) {
//如果未引入包此处会报org.apache.tomcat.jdbc.pool.PoolConfiguration未找到错误
//因为org.apache.tomcat.jdbc.pool.DataSource实现了此接口会首先检查接口的存在与否
// ignore
}
try {
return new BeeDSFactory(setting);
} catch (final NoClassDefFoundError | NoSuchMethodError e) {
// ignore
}
try {
return new DbcpDSFactory(setting);
} catch (final NoClassDefFoundError | NoSuchMethodError e) {
// ignore
}
try {
return new C3p0DSFactory(setting);
} catch (final NoClassDefFoundError | NoSuchMethodError e) {
// ignore
}
return new PooledDSFactory(setting);
}
// ------------------------------------------------------------------------- Static end
} }

View File

@ -0,0 +1,22 @@
package cn.hutool.db.ds;
/**
* 数据源配置的字段名
*
* @since 6.0.0
* @author Looly
*/
public interface DSKeys {
/** 某些数据库需要的特殊配置项需要的配置项 */
String[] KEY_CONN_PROPS = {"remarks", "useInformationSchema"};
/** 别名字段名URL */
String[] KEY_ALIAS_URL = { "url", "jdbcUrl" };
/** 别名字段名:驱动名 */
String[] KEY_ALIAS_DRIVER = { "driver", "driverClassName" };
/** 别名字段名:用户名 */
String[] KEY_ALIAS_USER = { "user", "username" };
/** 别名字段名:密码 */
String[] KEY_ALIAS_PASSWORD = { "pass", "password" };
}

View File

@ -0,0 +1,151 @@
package cn.hutool.db.ds;
import cn.hutool.db.DbRuntimeException;
import cn.hutool.db.ds.bee.BeeDSFactory;
import cn.hutool.db.ds.c3p0.C3p0DSFactory;
import cn.hutool.db.ds.dbcp.DbcpDSFactory;
import cn.hutool.db.ds.druid.DruidDSFactory;
import cn.hutool.db.ds.hikari.HikariDSFactory;
import cn.hutool.db.ds.pooled.PooledDSFactory;
import cn.hutool.db.ds.tomcat.TomcatDSFactory;
import cn.hutool.log.StaticLog;
import cn.hutool.setting.Setting;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
/**
* {@link DataSource}{@link DSFactory}相关工具类<br>
* 主要提供数据源工厂的创建和数据源的获取
*
* @author looly
* @since 6.0.0
*/
public class DSUtil {
/**
* 获得JNDI数据源
*
* @param jndiName JNDI名称
* @return 数据源
*/
public static DataSource getJndiDSWithLog(final String jndiName) {
try {
return getJndiDS(jndiName);
} catch (final DbRuntimeException e) {
StaticLog.error(e.getCause(), "Find JNDI datasource error!");
}
return null;
}
/**
* 获得JNDI数据源
*
* @param jndiName JNDI名称
* @return 数据源
*/
public static DataSource getJndiDS(final String jndiName) {
try {
return (DataSource) new InitialContext().lookup(jndiName);
} catch (final NamingException e) {
throw new DbRuntimeException(e);
}
}
/**
* 获得数据源<br>
* 使用默认配置文件的无分组配置
*
* @return 数据源
*/
public static DataSource getDS() {
return getDS(null);
}
/**
* 获得数据源
*
* @param group 配置文件中对应的分组
* @return 数据源
*/
public static DataSource getDS(final String group) {
return GlobalDSFactory.get().getDataSource(group);
}
/**
* 设置全局的数据源工厂<br>
* 在项目中存在多个连接池库的情况下我们希望使用低优先级的库时使用此方法自定义之<br>
* 重新定义全局的数据源工厂此方法可在以下两种情况下调用
*
* <pre>
* 1. 在get方法调用前调用此方法来自定义全局的数据源工厂
* 2. 替换已存在的全局数据源工厂当已存在时会自动关闭
* </pre>
*
* @param dsFactory 数据源工厂
* @return 自定义的数据源工厂
*/
public static DSFactory setGlobalDSFactory(final DSFactory dsFactory) {
return GlobalDSFactory.set(dsFactory);
}
/**
* 创建数据源实现工厂<br>
* 此方法通过试错方式查找引入项目的连接池库按照优先级寻找一旦寻找到则创建对应的数据源工厂<br>
* 连接池优先级Hikari &gt; Druid &gt; Tomcat &gt; Dbcp &gt; C3p0 &gt; Hutool Pooled
*
* @param setting 数据库配置项
* @return 日志实现类
*/
public static DSFactory createFactory(final Setting setting) {
final DSFactory dsFactory = _createFactory(setting);
StaticLog.debug("Use [{}] DataSource As Default", dsFactory.getDataSourceName());
return dsFactory;
}
/**
* 创建数据源实现工厂<br>
* 此方法通过试错方式查找引入项目的连接池库按照优先级寻找一旦寻找到则创建对应的数据源工厂<br>
* 连接池优先级Hikari &gt; Druid &gt; Tomcat &gt; BeeCP &gt; Dbcp &gt; C3p0 &gt; Hutool Pooled
*
* @param setting 数据库配置项
* @return 日志实现类
* @since 4.1.3
*/
private static DSFactory _createFactory(final Setting setting) {
try {
return new HikariDSFactory(setting);
} catch (final NoClassDefFoundError | NoSuchMethodError e) {
// ignore
}
try {
return new DruidDSFactory(setting);
} catch (final NoClassDefFoundError | NoSuchMethodError e) {
// ignore
}
try {
return new TomcatDSFactory(setting);
} catch (final NoClassDefFoundError | NoSuchMethodError e) {
//如果未引入包此处会报org.apache.tomcat.jdbc.pool.PoolConfiguration未找到错误
//因为org.apache.tomcat.jdbc.pool.DataSource实现了此接口会首先检查接口的存在与否
// ignore
}
try {
return new BeeDSFactory(setting);
} catch (final NoClassDefFoundError | NoSuchMethodError e) {
// ignore
}
try {
return new DbcpDSFactory(setting);
} catch (final NoClassDefFoundError | NoSuchMethodError e) {
// ignore
}
try {
return new C3p0DSFactory(setting);
} catch (final NoClassDefFoundError | NoSuchMethodError e) {
// ignore
}
return new PooledDSFactory(setting);
}
}

View File

@ -22,7 +22,7 @@ import java.util.logging.Logger;
* @author looly * @author looly
* @since 4.3.2 * @since 4.3.2
*/ */
public class DataSourceWrapper implements Wrapper<DataSource>, DataSource, Closeable, Cloneable { public class DSWrapper implements Wrapper<DataSource>, DataSource, Closeable, Cloneable {
private final DataSource ds; private final DataSource ds;
private final String driver; private final String driver;
@ -34,8 +34,8 @@ public class DataSourceWrapper implements Wrapper<DataSource>, DataSource, Close
* @param driver 数据库驱动类名 * @param driver 数据库驱动类名
* @return DataSourceWrapper * @return DataSourceWrapper
*/ */
public static DataSourceWrapper wrap(final DataSource ds, final String driver) { public static DSWrapper wrap(final DataSource ds, final String driver) {
return new DataSourceWrapper(ds, driver); return new DSWrapper(ds, driver);
} }
/** /**
@ -44,7 +44,7 @@ public class DataSourceWrapper implements Wrapper<DataSource>, DataSource, Close
* @param ds 原始的DataSource * @param ds 原始的DataSource
* @param driver 数据库驱动类名 * @param driver 数据库驱动类名
*/ */
public DataSourceWrapper(final DataSource ds, final String driver) { public DSWrapper(final DataSource ds, final String driver) {
this.ds = ds; this.ds = ds;
this.driver = driver; this.driver = driver;
} }
@ -121,9 +121,9 @@ public class DataSourceWrapper implements Wrapper<DataSource>, DataSource, Close
} }
@Override @Override
public DataSourceWrapper clone() { public DSWrapper clone() {
try { try {
return (DataSourceWrapper) super.clone(); return (DSWrapper) super.clone();
} catch (final CloneNotSupportedException e) { } catch (final CloneNotSupportedException e) {
throw new CloneRuntimeException(e); throw new CloneRuntimeException(e);
} }

View File

@ -1,9 +1,11 @@
package cn.hutool.db.ds; package cn.hutool.db.ds;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.log.StaticLog; import cn.hutool.log.StaticLog;
/** /**
* 全局数据源工厂<br> * 全局单例数据源工厂<br>
* 一般情况下一个应用默认只使用一种数据库连接池因此维护一个全局的数据源工厂类减少判断连接池类型造成的性能浪费 * 一般情况下一个应用默认只使用一种数据库连接池因此维护一个全局的数据源工厂类减少判断连接池类型造成的性能浪费
* *
* @author looly * @author looly
@ -19,14 +21,11 @@ public class GlobalDSFactory {
*/ */
static { static {
// JVM关闭时关闭所有连接池 // JVM关闭时关闭所有连接池
Runtime.getRuntime().addShutdownHook(new Thread() { RuntimeUtil.addShutdownHook(()->{
@Override if (null != factory) {
public void run() { IoUtil.close(factory);
if (null != factory) { StaticLog.debug("DataSource: [{}] closed.", factory.getDataSourceName());
factory.destroy(); factory = null;
StaticLog.debug("DataSource: [{}] destroyed.", factory.dataSourceName);
factory = null;
}
} }
}); });
} }
@ -42,7 +41,7 @@ public class GlobalDSFactory {
if (null == factory) { if (null == factory) {
synchronized (lock) { synchronized (lock) {
if (null == factory) { if (null == factory) {
factory = DSFactory.of(null); factory = DSUtil.createFactory(null);
} }
} }
} }
@ -69,10 +68,10 @@ public class GlobalDSFactory {
return factory;// 数据源工厂不变时返回原数据源工厂 return factory;// 数据源工厂不变时返回原数据源工厂
} }
// 自定义数据源工厂前关闭之前的数据源 // 自定义数据源工厂前关闭之前的数据源
factory.destroy(); IoUtil.close(factory);
} }
StaticLog.debug("Custom use [{}] DataSource.", customDSFactory.dataSourceName); StaticLog.debug("Custom use [{}] DataSource.", customDSFactory.getDataSourceName());
factory = customDSFactory; factory = customDSFactory;
} }
return factory; return factory;

View File

@ -4,6 +4,7 @@ import cn.beecp.BeeDataSource;
import cn.beecp.BeeDataSourceConfig; import cn.beecp.BeeDataSourceConfig;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.db.ds.AbstractDSFactory; import cn.hutool.db.ds.AbstractDSFactory;
import cn.hutool.db.ds.DSKeys;
import cn.hutool.setting.Setting; import cn.hutool.setting.Setting;
import javax.sql.DataSource; import javax.sql.DataSource;
@ -12,17 +13,27 @@ import javax.sql.DataSource;
* BeeCP数据源工厂类 * BeeCP数据源工厂类
* *
* @author Looly * @author Looly
*
*/ */
public class BeeDSFactory extends AbstractDSFactory { public class BeeDSFactory extends AbstractDSFactory {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/**
* 连接池名称BeeCP
*/
public static final String DS_NAME = "BeeCP"; public static final String DS_NAME = "BeeCP";
/**
* 构造使用默认配置文件
*/
public BeeDSFactory() { public BeeDSFactory() {
this(null); this(null);
} }
/**
* 构造使用自定义配置文件
*
* @param setting 配置文件
*/
public BeeDSFactory(final Setting setting) { public BeeDSFactory(final Setting setting) {
super(DS_NAME, BeeDataSource.class, setting); super(DS_NAME, BeeDataSource.class, setting);
} }
@ -35,9 +46,9 @@ public class BeeDSFactory extends AbstractDSFactory {
// remarks等特殊配置since 5.3.8 // remarks等特殊配置since 5.3.8
String connValue; String connValue;
for (final String key : KEY_CONN_PROPS) { for (final String key : DSKeys.KEY_CONN_PROPS) {
connValue = poolSetting.getAndRemove(key); connValue = poolSetting.getAndRemove(key);
if(StrUtil.isNotBlank(connValue)){ if (StrUtil.isNotBlank(connValue)) {
beeConfig.addConnectProperty(key, connValue); beeConfig.addConnectProperty(key, connValue);
} }
} }

View File

@ -4,6 +4,7 @@ import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.db.DbRuntimeException; import cn.hutool.db.DbRuntimeException;
import cn.hutool.db.ds.AbstractDSFactory; import cn.hutool.db.ds.AbstractDSFactory;
import cn.hutool.db.ds.DSKeys;
import cn.hutool.setting.Setting; import cn.hutool.setting.Setting;
import cn.hutool.setting.dialect.Props; import cn.hutool.setting.dialect.Props;
import com.mchange.v2.c3p0.ComboPooledDataSource; import com.mchange.v2.c3p0.ComboPooledDataSource;
@ -12,7 +13,7 @@ import javax.sql.DataSource;
import java.beans.PropertyVetoException; import java.beans.PropertyVetoException;
/** /**
* Druid数据源工厂类 * C3P0数据源工厂类
* *
* @author Looly * @author Looly
* *
@ -20,6 +21,9 @@ import java.beans.PropertyVetoException;
public class C3p0DSFactory extends AbstractDSFactory { public class C3p0DSFactory extends AbstractDSFactory {
private static final long serialVersionUID = -6090788225842047281L; private static final long serialVersionUID = -6090788225842047281L;
/**
* 数据源名称C3P0
*/
public static final String DS_NAME = "C3P0"; public static final String DS_NAME = "C3P0";
/** /**
@ -30,7 +34,7 @@ public class C3p0DSFactory extends AbstractDSFactory {
} }
/** /**
* 构造 * 构造使用自定义配置文件
* *
* @param setting 配置 * @param setting 配置
*/ */
@ -45,7 +49,7 @@ public class C3p0DSFactory extends AbstractDSFactory {
// remarks等特殊配置since 5.3.8 // remarks等特殊配置since 5.3.8
final Props connProps = new Props(); final Props connProps = new Props();
String connValue; String connValue;
for (final String key : KEY_CONN_PROPS) { for (final String key : DSKeys.KEY_CONN_PROPS) {
connValue = poolSetting.getAndRemove(key); connValue = poolSetting.getAndRemove(key);
if(StrUtil.isNotBlank(connValue)){ if(StrUtil.isNotBlank(connValue)){
connProps.setProperty(key, connValue); connProps.setProperty(key, connValue);

View File

@ -2,6 +2,7 @@ package cn.hutool.db.ds.dbcp;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.db.ds.AbstractDSFactory; import cn.hutool.db.ds.AbstractDSFactory;
import cn.hutool.db.ds.DSKeys;
import cn.hutool.setting.Setting; import cn.hutool.setting.Setting;
import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.BasicDataSource;
@ -16,12 +17,23 @@ import javax.sql.DataSource;
public class DbcpDSFactory extends AbstractDSFactory { public class DbcpDSFactory extends AbstractDSFactory {
private static final long serialVersionUID = -9133501414334104548L; private static final long serialVersionUID = -9133501414334104548L;
/**
* 数据源名称commons-dbcp2
*/
public static final String DS_NAME = "commons-dbcp2"; public static final String DS_NAME = "commons-dbcp2";
/**
* 构造使用默认配置文件
*/
public DbcpDSFactory() { public DbcpDSFactory() {
this(null); this(null);
} }
/**
* 构造使用自定义配置文件
*
* @param setting 配置
*/
public DbcpDSFactory(final Setting setting) { public DbcpDSFactory(final Setting setting) {
super(DS_NAME, BasicDataSource.class, setting); super(DS_NAME, BasicDataSource.class, setting);
} }
@ -37,7 +49,7 @@ public class DbcpDSFactory extends AbstractDSFactory {
// remarks等特殊配置since 5.3.8 // remarks等特殊配置since 5.3.8
String connValue; String connValue;
for (final String key : KEY_CONN_PROPS) { for (final String key : DSKeys.KEY_CONN_PROPS) {
connValue = poolSetting.getAndRemove(key); connValue = poolSetting.getAndRemove(key);
if(StrUtil.isNotBlank(connValue)){ if(StrUtil.isNotBlank(connValue)){
ds.addConnectionProperty(key, connValue); ds.addConnectionProperty(key, connValue);

View File

@ -2,6 +2,7 @@ package cn.hutool.db.ds.druid;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.db.ds.AbstractDSFactory; import cn.hutool.db.ds.AbstractDSFactory;
import cn.hutool.db.ds.DSKeys;
import cn.hutool.setting.Setting; import cn.hutool.setting.Setting;
import cn.hutool.setting.dialect.Props; import cn.hutool.setting.dialect.Props;
import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSource;
@ -17,6 +18,9 @@ import javax.sql.DataSource;
public class DruidDSFactory extends AbstractDSFactory { public class DruidDSFactory extends AbstractDSFactory {
private static final long serialVersionUID = 4680621702534433222L; private static final long serialVersionUID = 4680621702534433222L;
/**
* 数据源名称Druid
*/
public static final String DS_NAME = "Druid"; public static final String DS_NAME = "Druid";
/** /**
@ -27,9 +31,9 @@ public class DruidDSFactory extends AbstractDSFactory {
} }
/** /**
* 构造 * 构造使用自定义配置文件
* *
* @param setting 数据库配置 * @param setting 配置
*/ */
public DruidDSFactory(final Setting setting) { public DruidDSFactory(final Setting setting) {
super(DS_NAME, DruidDataSource.class, setting); super(DS_NAME, DruidDataSource.class, setting);
@ -48,7 +52,7 @@ public class DruidDSFactory extends AbstractDSFactory {
// remarks等特殊配置since 5.3.8 // remarks等特殊配置since 5.3.8
// Druid中也可以通过 druid.connectProperties 属性设置 // Druid中也可以通过 druid.connectProperties 属性设置
String connValue; String connValue;
for (final String key : KEY_CONN_PROPS) { for (final String key : DSKeys.KEY_CONN_PROPS) {
connValue = poolSetting.getAndRemove(key); connValue = poolSetting.getAndRemove(key);
if(StrUtil.isNotBlank(connValue)){ if(StrUtil.isNotBlank(connValue)){
ds.addConnectionProperty(key, connValue); ds.addConnectionProperty(key, connValue);

View File

@ -2,6 +2,7 @@ package cn.hutool.db.ds.hikari;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.db.ds.AbstractDSFactory; import cn.hutool.db.ds.AbstractDSFactory;
import cn.hutool.db.ds.DSKeys;
import cn.hutool.setting.Setting; import cn.hutool.setting.Setting;
import cn.hutool.setting.dialect.Props; import cn.hutool.setting.dialect.Props;
import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariConfig;
@ -18,12 +19,23 @@ import javax.sql.DataSource;
public class HikariDSFactory extends AbstractDSFactory { public class HikariDSFactory extends AbstractDSFactory {
private static final long serialVersionUID = -8834744983614749401L; private static final long serialVersionUID = -8834744983614749401L;
/**
* 数据源名称HikariCP
*/
public static final String DS_NAME = "HikariCP"; public static final String DS_NAME = "HikariCP";
/**
* 构造使用默认配置文件
*/
public HikariDSFactory() { public HikariDSFactory() {
this(null); this(null);
} }
/**
* 构造使用自定义配置文件
*
* @param setting 配置
*/
public HikariDSFactory(final Setting setting) { public HikariDSFactory(final Setting setting) {
super(DS_NAME, HikariDataSource.class, setting); super(DS_NAME, HikariDataSource.class, setting);
} }
@ -33,7 +45,7 @@ public class HikariDSFactory extends AbstractDSFactory {
// remarks等特殊配置since 5.3.8 // remarks等特殊配置since 5.3.8
final Props connProps = new Props(); final Props connProps = new Props();
String connValue; String connValue;
for (final String key : KEY_CONN_PROPS) { for (final String key : DSKeys.KEY_CONN_PROPS) {
connValue = poolSetting.getAndRemove(key); connValue = poolSetting.getAndRemove(key);
if(StrUtil.isNotBlank(connValue)){ if(StrUtil.isNotBlank(connValue)){
connProps.setProperty(key, connValue); connProps.setProperty(key, connValue);

View File

@ -1,20 +1,20 @@
package cn.hutool.db.ds.jndi; package cn.hutool.db.ds.jndi;
import javax.sql.DataSource;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.db.DbRuntimeException; import cn.hutool.db.DbRuntimeException;
import cn.hutool.db.DbUtil;
import cn.hutool.db.ds.AbstractDSFactory; import cn.hutool.db.ds.AbstractDSFactory;
import cn.hutool.db.ds.DSUtil;
import cn.hutool.setting.Setting; import cn.hutool.setting.Setting;
import javax.sql.DataSource;
/** /**
* JNDI数据源工厂类<br> * JNDI数据源工厂类<br>
* Setting配置样例<br> * Setting配置样例
* ---------------------<br> * <pre>
* [group]<br> * [group]
* jndi = jdbc/TestDB<br> * jndi = jdbc/TestDB
* ---------------------<br> * </pre>
* *
* @author Looly * @author Looly
* *
@ -22,12 +22,23 @@ import cn.hutool.setting.Setting;
public class JndiDSFactory extends AbstractDSFactory { public class JndiDSFactory extends AbstractDSFactory {
private static final long serialVersionUID = 1573625812927370432L; private static final long serialVersionUID = 1573625812927370432L;
/**
* 数据源名称JNDI DataSource
*/
public static final String DS_NAME = "JNDI DataSource"; public static final String DS_NAME = "JNDI DataSource";
/**
* 构造使用默认配置文件
*/
public JndiDSFactory() { public JndiDSFactory() {
this(null); this(null);
} }
/**
* 构造使用自定义配置文件
*
* @param setting 配置
*/
public JndiDSFactory(final Setting setting) { public JndiDSFactory(final Setting setting) {
super(DS_NAME, null, setting); super(DS_NAME, null, setting);
} }
@ -38,6 +49,6 @@ public class JndiDSFactory extends AbstractDSFactory {
if (StrUtil.isEmpty(jndiName)) { if (StrUtil.isEmpty(jndiName)) {
throw new DbRuntimeException("No setting name [jndi] for this group."); throw new DbRuntimeException("No setting name [jndi] for this group.");
} }
return DbUtil.getJndiDs(jndiName); return DSUtil.getJndiDS(jndiName);
} }
} }

View File

@ -1,7 +1,8 @@
/** /**
* 数据源封装对各类数据库连接池的封装 * 数据源封装对各类数据库连接池的封装<br>
* * 数据库连接池使用工厂方法模式当有新增连接池时实现{@link cn.hutool.db.ds.DSFactory}即可
*
* @author looly * @author looly
* *
*/ */
package cn.hutool.db.ds; package cn.hutool.db.ds;

View File

@ -4,7 +4,7 @@ import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.db.DbRuntimeException; import cn.hutool.db.DbRuntimeException;
import cn.hutool.db.dialect.DriverUtil; import cn.hutool.db.dialect.DriverUtil;
import cn.hutool.db.ds.DSFactory; import cn.hutool.db.ds.DSKeys;
import cn.hutool.setting.Setting; import cn.hutool.setting.Setting;
/** /**
@ -54,16 +54,16 @@ public class DbSetting {
final DbConfig dbConfig = new DbConfig(); final DbConfig dbConfig = new DbConfig();
// 基本信息 // 基本信息
final String url = config.getAndRemove(DSFactory.KEY_ALIAS_URL); final String url = config.getAndRemove(DSKeys.KEY_ALIAS_URL);
if (StrUtil.isBlank(url)) { if (StrUtil.isBlank(url)) {
throw new DbRuntimeException("No JDBC URL for group: [{}]", group); throw new DbRuntimeException("No JDBC URL for group: [{}]", group);
} }
dbConfig.setUrl(url); dbConfig.setUrl(url);
// 自动识别Driver // 自动识别Driver
final String driver = config.getAndRemove(DSFactory.KEY_ALIAS_DRIVER); final String driver = config.getAndRemove(DSKeys.KEY_ALIAS_DRIVER);
dbConfig.setDriver(StrUtil.isNotBlank(driver) ? driver : DriverUtil.identifyDriver(url)); dbConfig.setDriver(StrUtil.isNotBlank(driver) ? driver : DriverUtil.identifyDriver(url));
dbConfig.setUser(config.getAndRemove(DSFactory.KEY_ALIAS_USER)); dbConfig.setUser(config.getAndRemove(DSKeys.KEY_ALIAS_USER));
dbConfig.setPass(config.getAndRemove(DSFactory.KEY_ALIAS_PASSWORD)); dbConfig.setPass(config.getAndRemove(DSKeys.KEY_ALIAS_PASSWORD));
// 连接池相关信息 // 连接池相关信息
dbConfig.setInitialSize(setting.getIntByGroup("initialSize", group, 0)); dbConfig.setInitialSize(setting.getIntByGroup("initialSize", group, 0));
@ -73,7 +73,7 @@ public class DbSetting {
// remarks等特殊配置since 5.3.8 // remarks等特殊配置since 5.3.8
String connValue; String connValue;
for (final String key : DSFactory.KEY_CONN_PROPS) { for (final String key : DSKeys.KEY_CONN_PROPS) {
connValue = config.get(key); connValue = config.get(key);
if(StrUtil.isNotBlank(connValue)){ if(StrUtil.isNotBlank(connValue)){
dbConfig.addConnProps(key, connValue); dbConfig.addConnProps(key, connValue);

View File

@ -2,6 +2,7 @@ package cn.hutool.db.ds.pooled;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.db.ds.AbstractDSFactory; import cn.hutool.db.ds.AbstractDSFactory;
import cn.hutool.db.ds.DSKeys;
import cn.hutool.setting.Setting; import cn.hutool.setting.Setting;
import javax.sql.DataSource; import javax.sql.DataSource;
@ -15,12 +16,23 @@ import javax.sql.DataSource;
public class PooledDSFactory extends AbstractDSFactory { public class PooledDSFactory extends AbstractDSFactory {
private static final long serialVersionUID = 8093886210895248277L; private static final long serialVersionUID = 8093886210895248277L;
/**
* 数据源名称Hutool-Pooled-DataSource
*/
public static final String DS_NAME = "Hutool-Pooled-DataSource"; public static final String DS_NAME = "Hutool-Pooled-DataSource";
/**
* 构造使用默认配置文件
*/
public PooledDSFactory() { public PooledDSFactory() {
this(null); this(null);
} }
/**
* 构造使用自定义配置文件
*
* @param setting 配置
*/
public PooledDSFactory(final Setting setting) { public PooledDSFactory(final Setting setting) {
super(DS_NAME, PooledDataSource.class, setting); super(DS_NAME, PooledDataSource.class, setting);
} }
@ -41,7 +53,7 @@ public class PooledDSFactory extends AbstractDSFactory {
// remarks等特殊配置since 5.3.8 // remarks等特殊配置since 5.3.8
String connValue; String connValue;
for (final String key : KEY_CONN_PROPS) { for (final String key : DSKeys.KEY_CONN_PROPS) {
connValue = poolSetting.get(key); connValue = poolSetting.get(key);
if(StrUtil.isNotBlank(connValue)){ if(StrUtil.isNotBlank(connValue)){
dbConfig.addConnProps(key, connValue); dbConfig.addConnProps(key, connValue);

View File

@ -14,12 +14,23 @@ import javax.sql.DataSource;
public class SimpleDSFactory extends AbstractDSFactory { public class SimpleDSFactory extends AbstractDSFactory {
private static final long serialVersionUID = 4738029988261034743L; private static final long serialVersionUID = 4738029988261034743L;
/**
* 数据源名称Hutool-Simple-DataSource
*/
public static final String DS_NAME = "Hutool-Simple-DataSource"; public static final String DS_NAME = "Hutool-Simple-DataSource";
/**
* 构造使用默认配置文件
*/
public SimpleDSFactory() { public SimpleDSFactory() {
this(null); this(null);
} }
/**
* 构造使用自定义配置文件
*
* @param setting 配置
*/
public SimpleDSFactory(final Setting setting) { public SimpleDSFactory(final Setting setting) {
super(DS_NAME, SimpleDataSource.class, setting); super(DS_NAME, SimpleDataSource.class, setting);
} }

View File

@ -4,7 +4,7 @@ import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.db.DbRuntimeException; import cn.hutool.db.DbRuntimeException;
import cn.hutool.db.dialect.DriverUtil; import cn.hutool.db.dialect.DriverUtil;
import cn.hutool.db.ds.DSFactory; import cn.hutool.db.ds.DSKeys;
import cn.hutool.setting.Setting; import cn.hutool.setting.Setting;
import cn.hutool.setting.dialect.Props; import cn.hutool.setting.dialect.Props;
@ -34,25 +34,6 @@ public class SimpleDataSource extends AbstractDataSource {
private Properties connProps; private Properties connProps;
// -------------------------------------------------------------------- Fields end // -------------------------------------------------------------------- Fields end
/**
* 获得一个数据源
*
* @param group 数据源分组
* @return SimpleDataSource
*/
synchronized public static SimpleDataSource getDataSource(final String group) {
return new SimpleDataSource(group);
}
/**
* 获得一个数据源无分组
*
* @return SimpleDataSource
*/
synchronized public static SimpleDataSource getDataSource() {
return new SimpleDataSource();
}
// -------------------------------------------------------------------- Constructor start // -------------------------------------------------------------------- Constructor start
/** /**
* 构造 * 构造
@ -86,10 +67,10 @@ public class SimpleDataSource extends AbstractDataSource {
} }
init(// init(//
config.getAndRemove(DSFactory.KEY_ALIAS_URL), // config.getAndRemove(DSKeys.KEY_ALIAS_URL), //
config.getAndRemove(DSFactory.KEY_ALIAS_USER), // config.getAndRemove(DSKeys.KEY_ALIAS_USER), //
config.getAndRemove(DSFactory.KEY_ALIAS_PASSWORD), // config.getAndRemove(DSKeys.KEY_ALIAS_PASSWORD), //
config.getAndRemove(DSFactory.KEY_ALIAS_DRIVER)// config.getAndRemove(DSKeys.KEY_ALIAS_DRIVER)//
); );
// 其它连接参数 // 其它连接参数

View File

@ -2,6 +2,7 @@ package cn.hutool.db.ds.tomcat;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.db.ds.AbstractDSFactory; import cn.hutool.db.ds.AbstractDSFactory;
import cn.hutool.db.ds.DSKeys;
import cn.hutool.setting.Setting; import cn.hutool.setting.Setting;
import cn.hutool.setting.dialect.Props; import cn.hutool.setting.dialect.Props;
import org.apache.tomcat.jdbc.pool.DataSource; import org.apache.tomcat.jdbc.pool.DataSource;
@ -16,6 +17,9 @@ import org.apache.tomcat.jdbc.pool.PoolProperties;
public class TomcatDSFactory extends AbstractDSFactory { public class TomcatDSFactory extends AbstractDSFactory {
private static final long serialVersionUID = 4925514193275150156L; private static final long serialVersionUID = 4925514193275150156L;
/**
* 数据源名称Tomcat-Jdbc-Pool
*/
public static final String DS_NAME = "Tomcat-Jdbc-Pool"; public static final String DS_NAME = "Tomcat-Jdbc-Pool";
/** /**
@ -26,7 +30,7 @@ public class TomcatDSFactory extends AbstractDSFactory {
} }
/** /**
* 构造 * 构造自定义配置
* *
* @param setting Setting数据库配置 * @param setting Setting数据库配置
*/ */
@ -45,7 +49,7 @@ public class TomcatDSFactory extends AbstractDSFactory {
// remarks等特殊配置since 5.3.8 // remarks等特殊配置since 5.3.8
final Props connProps = new Props(); final Props connProps = new Props();
String connValue; String connValue;
for (final String key : KEY_CONN_PROPS) { for (final String key : DSKeys.KEY_CONN_PROPS) {
connValue = poolSetting.getAndRemove(key); connValue = poolSetting.getAndRemove(key);
if(StrUtil.isNotBlank(connValue)){ if(StrUtil.isNotBlank(connValue)){
connProps.setProperty(key, connValue); connProps.setProperty(key, connValue);

View File

@ -1,8 +1,8 @@
package cn.hutool.db; package cn.hutool.db;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.db.ds.DSFactory; import cn.hutool.db.ds.DSUtil;
import cn.hutool.db.ds.DataSourceWrapper; import cn.hutool.db.ds.DSWrapper;
import cn.hutool.db.ds.bee.BeeDSFactory; import cn.hutool.db.ds.bee.BeeDSFactory;
import cn.hutool.db.ds.c3p0.C3p0DSFactory; import cn.hutool.db.ds.c3p0.C3p0DSFactory;
import cn.hutool.db.ds.dbcp.DbcpDSFactory; import cn.hutool.db.ds.dbcp.DbcpDSFactory;
@ -27,7 +27,7 @@ public class DsTest {
@Test @Test
public void defaultDsTest() { public void defaultDsTest() {
final DataSource ds = DSFactory.get("test"); final DataSource ds = DSUtil.getDS("test");
final Db db = Db.of(ds); final Db db = Db.of(ds);
final List<Entity> all = db.findAll("user"); final List<Entity> all = db.findAll("user");
Assert.assertTrue(CollUtil.isNotEmpty(all)); Assert.assertTrue(CollUtil.isNotEmpty(all));
@ -35,8 +35,8 @@ public class DsTest {
@Test @Test
public void hikariDsTest() { public void hikariDsTest() {
DSFactory.setCurrentDSFactory(new HikariDSFactory()); DSUtil.setGlobalDSFactory(new HikariDSFactory());
final DataSource ds = DSFactory.get("test"); final DataSource ds = DSUtil.getDS("test");
final Db db = Db.of(ds); final Db db = Db.of(ds);
final List<Entity> all = db.findAll("user"); final List<Entity> all = db.findAll("user");
Assert.assertTrue(CollUtil.isNotEmpty(all)); Assert.assertTrue(CollUtil.isNotEmpty(all));
@ -44,8 +44,8 @@ public class DsTest {
@Test @Test
public void druidDsTest() { public void druidDsTest() {
DSFactory.setCurrentDSFactory(new DruidDSFactory()); DSUtil.setGlobalDSFactory(new DruidDSFactory());
final DataSource ds = DSFactory.get("test"); final DataSource ds = DSUtil.getDS("test");
final Db db = Db.of(ds); final Db db = Db.of(ds);
final List<Entity> all = db.findAll("user"); final List<Entity> all = db.findAll("user");
@ -54,8 +54,8 @@ public class DsTest {
@Test @Test
public void tomcatDsTest() { public void tomcatDsTest() {
DSFactory.setCurrentDSFactory(new TomcatDSFactory()); DSUtil.setGlobalDSFactory(new TomcatDSFactory());
final DataSource ds = DSFactory.get("test"); final DataSource ds = DSUtil.getDS("test");
final Db db = Db.of(ds); final Db db = Db.of(ds);
final List<Entity> all = db.findAll("user"); final List<Entity> all = db.findAll("user");
Assert.assertTrue(CollUtil.isNotEmpty(all)); Assert.assertTrue(CollUtil.isNotEmpty(all));
@ -63,8 +63,8 @@ public class DsTest {
@Test @Test
public void beeCPDsTest() { public void beeCPDsTest() {
DSFactory.setCurrentDSFactory(new BeeDSFactory()); DSUtil.setGlobalDSFactory(new BeeDSFactory());
final DataSource ds = DSFactory.get("test"); final DataSource ds = DSUtil.getDS("test");
final Db db = Db.of(ds); final Db db = Db.of(ds);
final List<Entity> all = db.findAll("user"); final List<Entity> all = db.findAll("user");
Assert.assertTrue(CollUtil.isNotEmpty(all)); Assert.assertTrue(CollUtil.isNotEmpty(all));
@ -72,8 +72,8 @@ public class DsTest {
@Test @Test
public void dbcpDsTest() { public void dbcpDsTest() {
DSFactory.setCurrentDSFactory(new DbcpDSFactory()); DSUtil.setGlobalDSFactory(new DbcpDSFactory());
final DataSource ds = DSFactory.get("test"); final DataSource ds = DSUtil.getDS("test");
final Db db = Db.of(ds); final Db db = Db.of(ds);
final List<Entity> all = db.findAll("user"); final List<Entity> all = db.findAll("user");
Assert.assertTrue(CollUtil.isNotEmpty(all)); Assert.assertTrue(CollUtil.isNotEmpty(all));
@ -81,8 +81,8 @@ public class DsTest {
@Test @Test
public void c3p0DsTest() { public void c3p0DsTest() {
DSFactory.setCurrentDSFactory(new C3p0DSFactory()); DSUtil.setGlobalDSFactory(new C3p0DSFactory());
final DataSource ds = DSFactory.get("test"); final DataSource ds = DSUtil.getDS("test");
final Db db = Db.of(ds); final Db db = Db.of(ds);
final List<Entity> all = db.findAll("user"); final List<Entity> all = db.findAll("user");
Assert.assertTrue(CollUtil.isNotEmpty(all)); Assert.assertTrue(CollUtil.isNotEmpty(all));
@ -91,16 +91,16 @@ public class DsTest {
@Test @Test
public void c3p0DsuserAndPassTest() { public void c3p0DsuserAndPassTest() {
// https://gitee.com/dromara/hutool/issues/I4T7XZ // https://gitee.com/dromara/hutool/issues/I4T7XZ
DSFactory.setCurrentDSFactory(new C3p0DSFactory()); DSUtil.setGlobalDSFactory(new C3p0DSFactory());
final ComboPooledDataSource ds = (ComboPooledDataSource) ((DataSourceWrapper) DSFactory.get("mysql")).getRaw(); final ComboPooledDataSource ds = (ComboPooledDataSource) ((DSWrapper) DSUtil.getDS("mysql")).getRaw();
Assert.assertEquals("root", ds.getUser()); Assert.assertEquals("root", ds.getUser());
Assert.assertEquals("123456", ds.getPassword()); Assert.assertEquals("123456", ds.getPassword());
} }
@Test @Test
public void hutoolPoolTest() { public void hutoolPoolTest() {
DSFactory.setCurrentDSFactory(new PooledDSFactory()); DSUtil.setGlobalDSFactory(new PooledDSFactory());
final DataSource ds = DSFactory.get("test"); final DataSource ds = DSUtil.getDS("test");
final Db db = Db.of(ds); final Db db = Db.of(ds);
final List<Entity> all = db.findAll("user"); final List<Entity> all = db.findAll("user");
Assert.assertTrue(CollUtil.isNotEmpty(all)); Assert.assertTrue(CollUtil.isNotEmpty(all));

View File

@ -9,9 +9,9 @@ public class DataSourceWrapperTest {
@Test @Test
public void cloneTest(){ public void cloneTest(){
final SimpleDataSource simpleDataSource = new SimpleDataSource("jdbc:sqlite:test.db", "", ""); final SimpleDataSource simpleDataSource = new SimpleDataSource("jdbc:sqlite:test.db", "", "");
final DataSourceWrapper wrapper = new DataSourceWrapper(simpleDataSource, "test.driver"); final DSWrapper wrapper = new DSWrapper(simpleDataSource, "test.driver");
final DataSourceWrapper clone = wrapper.clone(); final DSWrapper clone = wrapper.clone();
Assert.assertEquals("test.driver", clone.getDriver()); Assert.assertEquals("test.driver", clone.getDriver());
Assert.assertEquals(simpleDataSource, clone.getRaw()); Assert.assertEquals(simpleDataSource, clone.getRaw());
} }

View File

@ -3,7 +3,7 @@ package cn.hutool.db.meta;
import cn.hutool.core.collection.SetUtil; import cn.hutool.core.collection.SetUtil;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.core.text.split.SplitUtil; import cn.hutool.core.text.split.SplitUtil;
import cn.hutool.db.ds.DSFactory; import cn.hutool.db.ds.DSUtil;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -17,7 +17,7 @@ import java.util.List;
* *
*/ */
public class MetaUtilTest { public class MetaUtilTest {
final DataSource ds = DSFactory.get("test"); final DataSource ds = DSUtil.getDS("test");
@Test @Test
public void getTablesTest() { public void getTablesTest() {