diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/AbstractDb.java b/hutool-db/src/main/java/org/dromara/hutool/db/AbstractDb.java index 73c352232..943bf91a8 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/AbstractDb.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/AbstractDb.java @@ -66,7 +66,7 @@ public abstract class AbstractDb> extends DefaultConnect this.dbConfig = ((DSWrapper) ds).getDbConfig(); this.caseInsensitive = this.dbConfig.isCaseInsensitive(); } - this.runner = new DialectRunner(dialect); + this.runner = new DialectRunner(this.dbConfig, dialect); } // ------------------------------------------------------- Constructor end @@ -134,7 +134,7 @@ public abstract class AbstractDb> extends DefaultConnect * @throws DbException SQL执行异常 */ public Number queryNumber(final String sql, final Object... params) throws DbException { - return query(sql, new NumberHandler(), params); + return query(sql, NumberHandler.INSTANCE, params); } /** @@ -163,7 +163,7 @@ public abstract class AbstractDb> extends DefaultConnect Connection conn = null; try { conn = this.getConnection(); - return SqlExecutor.query(conn, sql, rsh, params); + return SqlExecutor.of(this.dbConfig, conn).query(sql, rsh, params); } finally { this.closeConnection(conn); } @@ -184,7 +184,7 @@ public abstract class AbstractDb> extends DefaultConnect Connection conn = null; try { conn = this.getConnection(); - return SqlExecutor.query(conn, sql, rsh, paramMap); + return SqlExecutor.of(this.dbConfig, conn).query(sql, rsh, paramMap); } finally { this.closeConnection(conn); } @@ -205,7 +205,7 @@ public abstract class AbstractDb> extends DefaultConnect Connection conn = null; try { conn = this.getConnection(); - return SqlExecutor.query(conn, statementFunc, rsh); + return SqlExecutor.of(this.dbConfig, conn).query(statementFunc, rsh); } finally { this.closeConnection(conn); } @@ -227,7 +227,7 @@ public abstract class AbstractDb> extends DefaultConnect Connection conn = null; try { conn = this.getConnection(); - return SqlExecutor.execute(conn, sql, params); + return SqlExecutor.of(this.dbConfig, conn).execute(sql, params); } finally { this.closeConnection(conn); } @@ -246,7 +246,7 @@ public abstract class AbstractDb> extends DefaultConnect Connection conn = null; try { conn = this.getConnection(); - return SqlExecutor.executeForGeneratedKey(conn, sql, params); + return SqlExecutor.of(this.dbConfig, conn).executeForGeneratedKey(sql, params); } finally { this.closeConnection(conn); } @@ -265,7 +265,7 @@ public abstract class AbstractDb> extends DefaultConnect Connection conn = null; try { conn = this.getConnection(); - return SqlExecutor.executeBatch(conn, sql, paramsBatch); + return SqlExecutor.of(this.dbConfig, conn).executeBatch(sql, paramsBatch); } finally { this.closeConnection(conn); } @@ -283,7 +283,7 @@ public abstract class AbstractDb> extends DefaultConnect Connection conn = null; try { conn = this.getConnection(); - return SqlExecutor.executeBatch(conn, sqls); + return SqlExecutor.of(this.dbConfig, conn).executeBatch(sqls); } finally { this.closeConnection(conn); } @@ -301,7 +301,7 @@ public abstract class AbstractDb> extends DefaultConnect Connection conn = null; try { conn = this.getConnection(); - return SqlExecutor.executeBatch(conn, sqls); + return SqlExecutor.of(this.dbConfig, conn).executeBatch(sqls); } finally { this.closeConnection(conn); } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/Db.java b/hutool-db/src/main/java/org/dromara/hutool/db/Db.java index 7feed2626..cf8e83b71 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/Db.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/Db.java @@ -13,6 +13,7 @@ package org.dromara.hutool.db; import org.dromara.hutool.core.func.SerConsumer; +import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.db.dialect.Dialect; import org.dromara.hutool.db.dialect.DialectFactory; import org.dromara.hutool.db.ds.DSUtil; @@ -33,6 +34,7 @@ import java.sql.SQLException; public class Db extends AbstractDb { private static final long serialVersionUID = -3378415769645309514L; + // region ----- of /** * 创建Db
* 使用默认数据源,自动探测数据库连接池 @@ -62,7 +64,7 @@ public class Db extends AbstractDb { * @return Db */ public static Db of(final DataSource ds) { - return ds == null ? null : new Db(ds); + return of(ds, DialectFactory.getDialect(ds)); } /** @@ -75,37 +77,7 @@ public class Db extends AbstractDb { public static Db of(final DataSource ds, final Dialect dialect) { return new Db(ds, dialect); } - - /** - * 创建Db - * - * @param ds 数据源 - * @param driverClassName 数据库连接驱动类名 - * @return Db - */ - public static Db of(final DataSource ds, final String driverClassName) { - return new Db(ds, DialectFactory.newDialect(driverClassName)); - } - - // ---------------------------------------------------------------------------- Constructor start - /** - * 构造,从DataSource中识别方言 - * - * @param ds 数据源 - */ - public Db(final DataSource ds) { - this(ds, DialectFactory.getDialect(ds)); - } - - /** - * 构造 - * - * @param ds 数据源 - * @param driverClassName 数据库连接驱动类名,用于识别方言 - */ - public Db(final DataSource ds, final String driverClassName) { - this(ds, DialectFactory.newDialect(driverClassName)); - } + // endregion /** * 构造 @@ -116,7 +88,6 @@ public class Db extends AbstractDb { public Db(final DataSource ds, final Dialect dialect) { super(ds, dialect); } - // ---------------------------------------------------------------------------- Constructor end /** * 执行事务,使用默认的事务级别
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/DialectRunner.java b/hutool-db/src/main/java/org/dromara/hutool/db/DialectRunner.java index 3062d2e1d..7b9a589cd 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/DialectRunner.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/DialectRunner.java @@ -18,12 +18,15 @@ import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.regex.PatternPool; import org.dromara.hutool.core.text.StrUtil; +import org.dromara.hutool.db.config.DbConfig; import org.dromara.hutool.db.dialect.Dialect; -import org.dromara.hutool.db.dialect.DialectFactory; import org.dromara.hutool.db.handler.NumberHandler; import org.dromara.hutool.db.handler.PageResultHandler; import org.dromara.hutool.db.handler.RsHandler; -import org.dromara.hutool.db.sql.*; +import org.dromara.hutool.db.sql.Query; +import org.dromara.hutool.db.sql.QuoteWrapper; +import org.dromara.hutool.db.sql.SqlBuilder; +import org.dromara.hutool.db.sql.SqlUtil; import java.io.Serializable; import java.sql.Connection; @@ -41,30 +44,19 @@ import java.util.regex.Pattern; public class DialectRunner implements Serializable { private static final long serialVersionUID = 1L; - private Dialect dialect; - /** - * 是否大小写不敏感(默认大小写不敏感) - */ - protected boolean caseInsensitive = true; + private final DbConfig config; + private final Dialect dialect; /** * 构造 * + * @param config 数据库配置 * @param dialect 方言 */ - public DialectRunner(final Dialect dialect) { + public DialectRunner(final DbConfig config, final Dialect dialect) { + this.config = config; this.dialect = dialect; } - - /** - * 构造 - * - * @param driverClassName 驱动类名,用于识别方言 - */ - public DialectRunner(final String driverClassName) { - this(DialectFactory.newDialect(driverClassName)); - } - //---------------------------------------------------------------------------- CRUD start /** @@ -114,10 +106,10 @@ public class DialectRunner implements Serializable { * @since 5.7.20 */ public int upsert(final Connection conn, final Entity record, final String... keys) throws DbException { - PreparedStatement ps = null; + PreparedStatement ps = this.dialect.psForUpsert(conn, record, keys); try { - ps = getDialect().psForUpsert(conn, record, keys); - } catch (final SQLException ignore) { + ps = this.dialect.psForUpsert(conn, record, keys); + } catch (final DbException ignore) { // 方言不支持,使用默认 } if (null != ps) { @@ -264,11 +256,7 @@ public class DialectRunner implements Serializable { public T find(final Connection conn, final Query query, final RsHandler rsh) throws DbException { checkConn(conn); Assert.notNull(query, "[query] is null !"); - try { - return SqlExecutor.queryAndClosePs(dialect.psForFind(conn, query), rsh); - } catch (final SQLException e) { - throw new DbException(e); - } + return StatementUtil.executeQuery(dialect.psForFind(conn, query), rsh); } /** @@ -281,11 +269,7 @@ public class DialectRunner implements Serializable { */ public long count(final Connection conn, final Query query) throws DbException { checkConn(conn); - try { - return SqlExecutor.queryAndClosePs(dialect.psForCount(conn, query), new NumberHandler()).longValue(); - } catch (final SQLException e) { - throw new DbException(e); - } + return StatementUtil.executeQuery(dialect.psForCount(conn, query), NumberHandler.INSTANCE).longValue(); } /** @@ -309,13 +293,8 @@ public class DialectRunner implements Serializable { selectSql = matcher.group(1); } - try { - return SqlExecutor.queryAndClosePs(dialect.psForCount(conn, - SqlBuilder.of(selectSql).addParams(sqlBuilder.getParamValueArray())), - new NumberHandler()).longValue(); - } catch (final SQLException e) { - throw new DbException(e); - } + return StatementUtil.executeQuery(dialect.psForCount(conn, + SqlBuilder.of(selectSql).addParams(sqlBuilder.getParamValueArray())), NumberHandler.INSTANCE).longValue(); } /** @@ -333,7 +312,7 @@ public class DialectRunner implements Serializable { // 分页查询中总数的查询要去掉分页信息 new PageResult<>(page, (int) count(conn, query.clone().setPage(null)))); - return page(conn, query, entityResultHandler.setCaseInsensitive(caseInsensitive)); + return page(conn, query, entityResultHandler.setCaseInsensitive(this.config.isCaseInsensitive())); } /** @@ -353,11 +332,7 @@ public class DialectRunner implements Serializable { return this.find(conn, query, rsh); } - try { - return SqlExecutor.queryAndClosePs(dialect.psForPage(conn, query), rsh); - } catch (final SQLException e) { - throw new DbException(e); - } + return StatementUtil.executeQuery(dialect.psForPage(conn, query), rsh); } /** @@ -374,7 +349,7 @@ public class DialectRunner implements Serializable { final PageResultHandler entityResultHandler = PageResultHandler.of( new PageResult<>(page, (int) count(conn, sqlBuilder))); - return page(conn, sqlBuilder, page, entityResultHandler.setCaseInsensitive(caseInsensitive)); + return page(conn, sqlBuilder, page, entityResultHandler.setCaseInsensitive(this.config.isCaseInsensitive())); } /** @@ -392,49 +367,10 @@ public class DialectRunner implements Serializable { */ public T page(final Connection conn, final SqlBuilder sqlBuilder, final Page page, final RsHandler rsh) throws DbException { checkConn(conn); - if (null == page) { - return SqlExecutor.query(conn, sqlBuilder, rsh); - } - - final PreparedStatement ps; - try { - ps = dialect.psForPage(conn, sqlBuilder, page); - } catch (final SQLException e) { - throw new DbException(e); - } - return SqlExecutor.queryAndClosePs(ps, rsh); + return StatementUtil.executeQuery(dialect.psForPage(conn, sqlBuilder, page), rsh); } //---------------------------------------------------------------------------- CRUD end - //---------------------------------------------------------------------------- Getters and Setters start - - /** - * 设置是否在结果中忽略大小写
- * 如果忽略,则在Entity中调用getXXX时,字段值忽略大小写,默认忽略 - * - * @param caseInsensitive 否在结果中忽略大小写 - * @since 5.2.4 - */ - public void setCaseInsensitive(final boolean caseInsensitive) { - this.caseInsensitive = caseInsensitive; - } - - /** - * @return SQL方言 - */ - public Dialect getDialect() { - return dialect; - } - - /** - * 设置SQL方言 - * - * @param dialect 方言 - */ - public void setDialect(final Dialect dialect) { - this.dialect = dialect; - } - /** * 设置包装器,包装器用于对表名、字段名进行符号包装(例如双引号),防止关键字与这些表名或字段冲突 * @@ -452,11 +388,12 @@ public class DialectRunner implements Serializable { public void setWrapper(final QuoteWrapper quoteWrapper) { this.dialect.setWrapper(quoteWrapper); } - //---------------------------------------------------------------------------- Getters and Setters end - //---------------------------------------------------------------------------- Private method start + /** + * 检查{@link Connection} 可用性 + * @param conn 数据库连接 + */ private void checkConn(final Connection conn) { Assert.notNull(conn, "Connection object must be not null!"); } - //---------------------------------------------------------------------------- Private method start } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/Session.java b/hutool-db/src/main/java/org/dromara/hutool/db/Session.java index 805b7e3cc..7203fa3f8 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/Session.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/Session.java @@ -79,16 +79,6 @@ public class Session extends AbstractDb implements Closeable { this(ds, DialectFactory.getDialect(ds)); } - /** - * 构造 - * - * @param ds 数据源 - * @param driverClassName 数据库连接驱动类名,用于识别方言 - */ - public Session(final DataSource ds, final String driverClassName) { - this(ds, DialectFactory.newDialect(driverClassName)); - } - /** * 构造 * @@ -279,21 +269,6 @@ public class Session extends AbstractDb implements Closeable { // ---------------------------------------------------------------------------- Transaction method end - @Override - public void closeConnection(final Connection conn) { - try { - if(conn != null && false == conn.getAutoCommit()) { - // 事务中的Session忽略关闭事件 - return; - } - } catch (final SQLException e) { - log.error(e); - } - - // 普通请求关闭(或归还)连接 - ThreadLocalConnection.INSTANCE.close(this.ds); - } - @Override public void close() { closeConnection(null); diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/StatementUtil.java b/hutool-db/src/main/java/org/dromara/hutool/db/StatementUtil.java index a5fcc078a..0bee8f817 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/StatementUtil.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/StatementUtil.java @@ -14,7 +14,9 @@ package org.dromara.hutool.db; import org.dromara.hutool.core.array.ArrayUtil; import org.dromara.hutool.core.collection.iter.ArrayIter; +import org.dromara.hutool.core.io.IoUtil; import org.dromara.hutool.core.lang.Assert; +import org.dromara.hutool.db.config.DbConfig; import org.dromara.hutool.db.handler.ResultSetUtil; import org.dromara.hutool.db.handler.RsHandler; import org.dromara.hutool.db.sql.SqlBuilder; @@ -34,47 +36,22 @@ import java.util.Map; */ public class StatementUtil { - /** - * 创建{@link PreparedStatement} - * - * @param conn 数据库连接 - * @param sqlBuilder {@link SqlBuilder}包括SQL语句和参数 - * @return {@link PreparedStatement} - * @since 4.1.3 - */ - public static PreparedStatement prepareStatement(final Connection conn, final SqlBuilder sqlBuilder) { - return prepareStatement(conn, sqlBuilder.build(), sqlBuilder.getParamValueArray()); - } - - /** - * 创建{@link PreparedStatement} - * - * @param conn 数据库连接 - * @param sql SQL语句,使用"?"做为占位符 - * @param params "?"对应参数列表或者Map表示命名参数 - * @return {@link PreparedStatement} - * @since 3.2.3 - */ - public static PreparedStatement prepareStatement(final Connection conn, final String sql, final Object... params) { - return prepareStatement(true, conn, sql, params); - } - /** * 创建{@link PreparedStatement} * * @param returnGeneratedKey 当为insert语句时,是否返回主键 - * @param conn 数据库连接 - * @param sql SQL语句,使用"?"做为占位符 - * @param params "?"对应参数列表或者Map表示命名参数 + * @param config 数据库配置 + * @param conn 数据库连接 + * @param sql SQL语句,使用"?"做为占位符 + * @param params "?"对应参数列表或者Map表示命名参数 * @return {@link PreparedStatement} * @since 5.8.19 */ - public static PreparedStatement prepareStatement(final boolean returnGeneratedKey, - final Connection conn, final String sql, final Object... params) { + public static PreparedStatement prepareStatement(final boolean returnGeneratedKey, final DbConfig config, final Connection conn, final String sql, final Object... params) { return StatementBuilder.of() .setConnection(conn) .setReturnGeneratedKey(returnGeneratedKey) - .setSqlFilter(SqlLogFilter.INSTANCE) + .setSqlFilter(config.getSqlFilters()) .setSql(sql) .setParams(params) .build(); @@ -83,31 +60,33 @@ public class StatementUtil { /** * 创建批量操作的{@link PreparedStatement} * + * @param config 数据库配置 * @param conn 数据库连接 * @param sql SQL语句,使用"?"做为占位符 * @param paramsBatch "?"对应参数批次列表 * @return {@link PreparedStatement} * @since 4.1.13 */ - public static PreparedStatement prepareStatementForBatch(final Connection conn, final String sql, final Object[]... paramsBatch) { - return prepareStatementForBatch(conn, sql, new ArrayIter<>(paramsBatch)); + public static PreparedStatement prepareStatementForBatch(final DbConfig config, final Connection conn, final String sql, final Object[]... paramsBatch) { + return prepareStatementForBatch(config, conn, sql, new ArrayIter<>(paramsBatch)); } /** * 创建批量操作的{@link PreparedStatement} * + * @param config 数据库配置 * @param conn 数据库连接 * @param sql SQL语句,使用"?"做为占位符 * @param paramsBatch "?"对应参数批次列表 * @return {@link PreparedStatement} * @since 4.1.13 */ - public static PreparedStatement prepareStatementForBatch(final Connection conn, final String sql, + public static PreparedStatement prepareStatementForBatch(final DbConfig config, final Connection conn, final String sql, final Iterable paramsBatch) { return StatementBuilder.of() .setConnection(conn) .setReturnGeneratedKey(false) - .setSqlFilter(SqlLogFilter.INSTANCE) + .setSqlFilter(config.getSqlFilters()) .setSql(sql) .setParams(ArrayUtil.ofArray(paramsBatch, Object.class)) .buildForBatch(); @@ -116,6 +95,7 @@ public class StatementUtil { /** * 创建{@link CallableStatement} * + * @param config 数据库配置 * @param conn 数据库连接 * @param sql SQL语句,使用"?"做为占位符 * @param params "?"对应参数列表 @@ -123,10 +103,10 @@ public class StatementUtil { * @throws SQLException SQL异常 * @since 4.1.13 */ - public static CallableStatement prepareCall(final Connection conn, final String sql, final Object... params) throws SQLException { + public static CallableStatement prepareCall(final DbConfig config, final Connection conn, final String sql, final Object... params) throws SQLException { return StatementBuilder.of() .setConnection(conn) - .setSqlFilter(SqlLogFilter.INSTANCE) + .setSqlFilter(config.getSqlFilters()) .setSql(sql) .setParams(params) .buildForCall(); @@ -250,4 +230,47 @@ public class StatementUtil { public static void setParam(final PreparedStatement ps, final int paramIndex, final Object param) throws SQLException { StatementWrapper.of(ps).setParam(paramIndex, param); } + + /** + * 执行查询 + * + * @param ps {@link PreparedStatement} + * @param rsh 结果集处理对象 + * @param 结果类型 + * @return 结果对象 + * @throws DbException SQL执行异常 + * @since 4.1.13 + */ + public static T executeQuery(final PreparedStatement ps, final RsHandler rsh) throws DbException { + ResultSet rs = null; + try { + rs = ps.executeQuery(); + return rsh.handle(rs); + } catch (final SQLException e) { + throw new DbException(e); + } finally { + IoUtil.closeQuietly(rs); + } + } + + /** + * 用于执行 INSERT、UPDATE 或 DELETE 语句以及 SQL DDL(数据定义语言)语句,例如 CREATE TABLE 和 DROP TABLE。
+ * INSERT、UPDATE 或 DELETE 语句的效果是修改表中零行或多行中的一列或多列。
+ * executeUpdate 的返回值是一个整数(int),指示受影响的行数(即更新计数)。
+ * 对于 CREATE TABLE 或 DROP TABLE 等不操作行的语句,executeUpdate 的返回值总为零。
+ * 此方法不会关闭PreparedStatement + * + * @param ps PreparedStatement对象 + * @param params 参数 + * @return 影响的行数 + * @throws DbException SQL执行异常 + */ + public static int executeUpdate(final PreparedStatement ps, final Object... params) throws DbException { + try { + StatementUtil.fillArrayParam(ps, params); + return ps.executeUpdate(); + } catch (final SQLException e) { + throw new DbException(e); + } + } } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/config/DbConfig.java b/hutool-db/src/main/java/org/dromara/hutool/db/config/DbConfig.java index 970d058bd..ccf99ec38 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/config/DbConfig.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/config/DbConfig.java @@ -12,6 +12,7 @@ package org.dromara.hutool.db.config; +import org.dromara.hutool.db.Db; import org.dromara.hutool.db.driver.DriverUtil; import org.dromara.hutool.db.sql.filter.SqlFilter; import org.dromara.hutool.db.sql.filter.SqlFilterChain; @@ -280,6 +281,15 @@ public class DbConfig { return this; } + /** + * 获取SQL过滤器 + * + * @return SQL过滤器 + */ + public SqlFilterChain getSqlFilters(){ + return this.sqlFilters; + } + /** * 增加SQL过滤器 * diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/config/SettingConfigParser.java b/hutool-db/src/main/java/org/dromara/hutool/db/config/SettingConfigParser.java index 842c02d15..74b494053 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/config/SettingConfigParser.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/config/SettingConfigParser.java @@ -18,6 +18,9 @@ import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.db.DbException; import org.dromara.hutool.db.driver.DriverUtil; +import org.dromara.hutool.db.sql.SqlLog; +import org.dromara.hutool.db.sql.filter.SqlLogFilter; +import org.dromara.hutool.log.level.Level; import org.dromara.hutool.setting.Setting; import org.dromara.hutool.setting.props.Props; @@ -61,16 +64,19 @@ public class SettingConfigParser implements ConfigParser { } @Override - public DbConfig parse(String group) { - if (group == null) { - group = StrUtil.EMPTY; - } - - final Setting subSetting = setting.getSetting(group); + public DbConfig parse(final String group) { + final Setting setting = this.setting; + final Setting subSetting = setting.getSetting(StrUtil.emptyIfNull(group)); if (MapUtil.isEmpty(subSetting)) { throw new DbException("No config for group: [{}]", group); } + // 继承属性 + subSetting.putIfAbsent(DSKeys.KEY_SHOW_SQL, setting.get(DSKeys.KEY_SHOW_SQL)); + subSetting.putIfAbsent(DSKeys.KEY_FORMAT_SQL, setting.get(DSKeys.KEY_FORMAT_SQL)); + subSetting.putIfAbsent(DSKeys.KEY_SHOW_PARAMS, setting.get(DSKeys.KEY_SHOW_PARAMS)); + subSetting.putIfAbsent(DSKeys.KEY_SQL_LEVEL, setting.get(DSKeys.KEY_SQL_LEVEL)); + return toDbConfig(subSetting); } @@ -108,9 +114,7 @@ public class SettingConfigParser implements ConfigParser { throw new DbException("No JDBC URL!"); } - // 移除用户可能误加入的show sql配置项 - // issue#I3VW0R@Gitee - removeShowSqlParams(setting); + final SqlLogFilter sqlLogFilter = getSqlLogFilter(setting); // 自动识别Driver String driver = setting.getAndRemove(DSKeys.KEY_ALIAS_DRIVER); @@ -122,7 +126,8 @@ public class SettingConfigParser implements ConfigParser { .setUrl(url) .setDriver(driver) .setUser(setting.getAndRemove(DSKeys.KEY_ALIAS_USER)) - .setPass(setting.getAndRemove(DSKeys.KEY_ALIAS_PASSWORD)); + .setPass(setting.getAndRemove(DSKeys.KEY_ALIAS_PASSWORD)) + .addSqlFilter(sqlLogFilter); // 大小写等配置 final String caseInsensitive = setting.getAndRemove(DSKeys.KEY_CASE_INSENSITIVE); @@ -164,12 +169,22 @@ public class SettingConfigParser implements ConfigParser { * 此方法用于移除用户配置在分组下的配置项目 * * @param setting 配置项 - * @since 5.7.2 + * @return {@link SqlLogFilter} */ - private static void removeShowSqlParams(final Setting setting) { - setting.remove(DSKeys.KEY_SHOW_SQL); - setting.remove(DSKeys.KEY_FORMAT_SQL); - setting.remove(DSKeys.KEY_SHOW_PARAMS); - setting.remove(DSKeys.KEY_SQL_LEVEL); + private static SqlLogFilter getSqlLogFilter(final Setting setting) { + // 初始化SQL显示 + final boolean isShowSql = Convert.toBoolean(setting.remove(DSKeys.KEY_SHOW_SQL), false); + final boolean isFormatSql = Convert.toBoolean(setting.remove(DSKeys.KEY_FORMAT_SQL), false); + final boolean isShowParams = Convert.toBoolean(setting.remove(DSKeys.KEY_SHOW_PARAMS), false); + String sqlLevelStr = setting.remove(DSKeys.KEY_SQL_LEVEL); + if (null != sqlLevelStr) { + sqlLevelStr = sqlLevelStr.toUpperCase(); + } + final Level level = Convert.toEnum(Level.class, sqlLevelStr, Level.DEBUG); + + final SqlLog sqlLog = new SqlLog(); + sqlLog.init(isShowSql, isFormatSql, isShowParams, level); + + return new SqlLogFilter(sqlLog); } } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/Dialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/Dialect.java index 63aa812e6..7654dc7ef 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/Dialect.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/Dialect.java @@ -12,6 +12,7 @@ package org.dromara.hutool.db.dialect; +import org.dromara.hutool.db.DbException; import org.dromara.hutool.db.Entity; import org.dromara.hutool.db.Page; import org.dromara.hutool.db.sql.Order; @@ -54,9 +55,9 @@ public interface Dialect extends Serializable { * @param conn 数据库连接对象 * @param entity 数据实体类(包含表名) * @return PreparedStatement - * @throws SQLException SQL执行异常 + * @throws DbException SQL执行异常 */ - PreparedStatement psForInsert(Connection conn, Entity entity) throws SQLException; + PreparedStatement psForInsert(Connection conn, Entity entity) throws DbException; /** * 构建用于批量插入的PreparedStatement
@@ -65,9 +66,9 @@ public interface Dialect extends Serializable { * @param conn 数据库连接对象 * @param entities 数据实体,实体的结构必须全部一致,否则插入结果将不可预知 * @return PreparedStatement - * @throws SQLException SQL执行异常 + * @throws DbException SQL执行异常 */ - PreparedStatement psForInsertBatch(Connection conn, Entity... entities) throws SQLException; + PreparedStatement psForInsertBatch(Connection conn, Entity... entities) throws DbException; /** * 构建用于删除的{@link PreparedStatement}
@@ -77,9 +78,9 @@ public interface Dialect extends Serializable { * @param conn 数据库连接对象 * @param query 查找条件(包含表名) * @return PreparedStatement - * @throws SQLException SQL执行异常 + * @throws DbException SQL执行异常 */ - PreparedStatement psForDelete(Connection conn, Query query) throws SQLException; + PreparedStatement psForDelete(Connection conn, Query query) throws DbException; /** * 构建用于更新的{@link PreparedStatement}
@@ -90,9 +91,9 @@ public interface Dialect extends Serializable { * @param entity 数据实体类(包含表名) * @param query 查找条件(包含表名) * @return PreparedStatement - * @throws SQLException SQL执行异常 + * @throws DbException SQL执行异常 */ - PreparedStatement psForUpdate(Connection conn, Entity entity, Query query) throws SQLException; + PreparedStatement psForUpdate(Connection conn, Entity entity, Query query) throws DbException; // -------------------------------------------- Query @@ -104,9 +105,9 @@ public interface Dialect extends Serializable { * @param conn 数据库连接对象 * @param query 查询条件(包含表名) * @return PreparedStatement - * @throws SQLException SQL执行异常 + * @throws DbException SQL执行异常 */ - PreparedStatement psForFind(Connection conn, Query query) throws SQLException; + PreparedStatement psForFind(Connection conn, Query query) throws DbException; /** * 构建用于分页查询的{@link PreparedStatement}
@@ -116,9 +117,9 @@ public interface Dialect extends Serializable { * @param conn 数据库连接对象 * @param query 查询条件(包含表名) * @return PreparedStatement - * @throws SQLException SQL执行异常 + * @throws DbException SQL执行异常 */ - PreparedStatement psForPage(Connection conn, Query query) throws SQLException; + PreparedStatement psForPage(Connection conn, Query query) throws DbException; /** * 构建用于分页查询的{@link PreparedStatement}
@@ -129,10 +130,10 @@ public interface Dialect extends Serializable { * @param sqlBuilder SQL构建器,可以使用{@link SqlBuilder#of(CharSequence)} 包装普通SQL * @param page 分页对象 * @return PreparedStatement - * @throws SQLException SQL执行异常 + * @throws DbException SQL执行异常 * @since 5.5.3 */ - PreparedStatement psForPage(Connection conn, SqlBuilder sqlBuilder, Page page) throws SQLException; + PreparedStatement psForPage(Connection conn, SqlBuilder sqlBuilder, Page page) throws DbException; /** * 构建用于查询行数的{@link PreparedStatement}
@@ -142,9 +143,9 @@ public interface Dialect extends Serializable { * @param conn 数据库连接对象 * @param query 查询条件(包含表名) * @return PreparedStatement - * @throws SQLException SQL执行异常 + * @throws DbException SQL执行异常 */ - default PreparedStatement psForCount(final Connection conn, final Query query) throws SQLException { + default PreparedStatement psForCount(final Connection conn, final Query query) throws DbException { return psForCount(conn, SqlBuilder.of().query(query)); } @@ -156,10 +157,10 @@ public interface Dialect extends Serializable { * @param conn 数据库连接对象 * @param sqlBuilder 查询语句,应该包含分页等信息 * @return PreparedStatement - * @throws SQLException SQL执行异常 + * @throws DbException SQL执行异常 * @since 5.7.2 */ - default PreparedStatement psForCount(final Connection conn, SqlBuilder sqlBuilder) throws SQLException { + default PreparedStatement psForCount(final Connection conn, SqlBuilder sqlBuilder) throws DbException { // https://gitee.com/dromara/hutool/issues/I713XQ // 为了兼容informix等数据库,此处使用count(*)而非count(1) sqlBuilder = sqlBuilder @@ -177,11 +178,11 @@ public interface Dialect extends Serializable { * @param entity 数据实体类(包含表名) * @param keys 查找字段,某些数据库此字段必须,如H2,某些数据库无需此字段,如MySQL(通过主键) * @return PreparedStatement - * @throws SQLException SQL执行异常,或方言数据不支持此操作 + * @throws DbException SQL执行异常,或方言数据不支持此操作 * @since 5.7.20 */ - default PreparedStatement psForUpsert(final Connection conn, final Entity entity, final String... keys) throws SQLException { - throw new SQLException("Unsupported upsert operation of " + dialectName()); + default PreparedStatement psForUpsert(final Connection conn, final Entity entity, final String... keys) throws DbException { + throw new DbException("Unsupported upsert operation of " + dialectName()); } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/DialectFactory.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/DialectFactory.java index ab5324090..84b0392d8 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/DialectFactory.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/DialectFactory.java @@ -14,19 +14,12 @@ package org.dromara.hutool.db.dialect; import org.dromara.hutool.core.map.SafeConcurrentHashMap; import org.dromara.hutool.core.text.StrUtil; -import org.dromara.hutool.db.driver.DriverUtil; -import org.dromara.hutool.db.dialect.impl.AnsiSqlDialect; -import org.dromara.hutool.db.dialect.impl.H2Dialect; -import org.dromara.hutool.db.dialect.impl.MysqlDialect; -import org.dromara.hutool.db.dialect.impl.OracleDialect; -import org.dromara.hutool.db.dialect.impl.PhoenixDialect; -import org.dromara.hutool.db.dialect.impl.PostgresqlDialect; -import org.dromara.hutool.db.dialect.impl.SqlServer2012Dialect; -import org.dromara.hutool.db.dialect.impl.Sqlite3Dialect; +import org.dromara.hutool.db.config.DbConfig; +import org.dromara.hutool.db.dialect.impl.*; +import org.dromara.hutool.db.ds.DSWrapper; import org.dromara.hutool.log.LogUtil; import javax.sql.DataSource; -import java.sql.Connection; import java.util.Map; /** @@ -45,11 +38,11 @@ public class DialectFactory implements DriverNamePool { * 根据驱动名创建方言
* 驱动名是不分区大小写完全匹配的 * - * @param driverName JDBC驱动类名 + * @param dbConfig 数据库配置 * @return 方言 */ - public static Dialect newDialect(final String driverName) { - final Dialect dialect = internalNewDialect(driverName); + public static Dialect newDialect(final DbConfig dbConfig) { + final Dialect dialect = internalNewDialect(dbConfig); LogUtil.debug("Use Dialect: [{}].", dialect.getClass().getSimpleName()); return dialect; } @@ -58,29 +51,31 @@ public class DialectFactory implements DriverNamePool { * 根据驱动名创建方言
* 驱动名是不分区大小写完全匹配的 * - * @param driverName JDBC驱动类名 + * @param dbConfig 数据库配置 * @return 方言 */ - private static Dialect internalNewDialect(final String driverName) { + private static Dialect internalNewDialect(final DbConfig dbConfig) { + final String driverName = dbConfig.getDriver(); + if (StrUtil.isNotBlank(driverName)) { if (DRIVER_MYSQL.equalsIgnoreCase(driverName) || DRIVER_MYSQL_V6.equalsIgnoreCase(driverName)) { - return new MysqlDialect(); + return new MysqlDialect(dbConfig); } else if (DRIVER_ORACLE.equalsIgnoreCase(driverName) || DRIVER_ORACLE_OLD.equalsIgnoreCase(driverName)) { - return new OracleDialect(); + return new OracleDialect(dbConfig); } else if (DRIVER_SQLLITE3.equalsIgnoreCase(driverName)) { - return new Sqlite3Dialect(); + return new Sqlite3Dialect(dbConfig); } else if (DRIVER_POSTGRESQL.equalsIgnoreCase(driverName)) { - return new PostgresqlDialect(); + return new PostgresqlDialect(dbConfig); } else if (DRIVER_H2.equalsIgnoreCase(driverName)) { - return new H2Dialect(); + return new H2Dialect(dbConfig); } else if (DRIVER_SQLSERVER.equalsIgnoreCase(driverName)) { - return new SqlServer2012Dialect(); + return new SqlServer2012Dialect(dbConfig); } else if (DRIVER_PHOENIX.equalsIgnoreCase(driverName)) { - return new PhoenixDialect(); + return new PhoenixDialect(dbConfig); } } // 无法识别可支持的数据库类型默认使用ANSI方言,可兼容大部分SQL语句 - return new AnsiSqlDialect(); + return new AnsiSqlDialect(dbConfig); } /** @@ -108,17 +103,6 @@ public class DialectFactory implements DriverNamePool { * @return 方言 */ public static Dialect newDialect(final DataSource ds) { - return newDialect(DriverUtil.identifyDriver(ds)); + return newDialect(ds instanceof DSWrapper ? ((DSWrapper) ds).getDbConfig() : DbConfig.of()); } - - /** - * 创建方言 - * - * @param conn 数据库连接对象 - * @return 方言 - */ - public static Dialect newDialect(final Connection conn) { - return newDialect(DriverUtil.identifyDriver(conn)); - } - } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/AnsiSqlDialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/AnsiSqlDialect.java index 54b9c3727..8d5c2d8f8 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/AnsiSqlDialect.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/AnsiSqlDialect.java @@ -18,6 +18,7 @@ import org.dromara.hutool.db.DbException; import org.dromara.hutool.db.Entity; import org.dromara.hutool.db.Page; import org.dromara.hutool.db.StatementUtil; +import org.dromara.hutool.db.config.DbConfig; import org.dromara.hutool.db.dialect.Dialect; import org.dromara.hutool.db.dialect.DialectName; import org.dromara.hutool.db.sql.Condition; @@ -27,7 +28,6 @@ import org.dromara.hutool.db.sql.SqlBuilder; import java.sql.Connection; import java.sql.PreparedStatement; -import java.sql.SQLException; /** * ANSI SQL 方言 @@ -37,8 +37,18 @@ import java.sql.SQLException; public class AnsiSqlDialect implements Dialect { private static final long serialVersionUID = 2088101129774974580L; + protected DbConfig dbConfig; protected QuoteWrapper quoteWrapper = new QuoteWrapper(); + /** + * 构造 + * + * @param dbConfig 数据库配置 + */ + public AnsiSqlDialect(final DbConfig dbConfig) { + this.dbConfig = dbConfig; + } + @Override public QuoteWrapper getWrapper() { return this.quoteWrapper; @@ -53,7 +63,7 @@ public class AnsiSqlDialect implements Dialect { public PreparedStatement psForInsert(final Connection conn, final Entity entity) { final SqlBuilder insert = SqlBuilder.of(quoteWrapper).insert(entity, this.dialectName()); - return StatementUtil.prepareStatement(conn, insert); + return StatementUtil.prepareStatement(this.dbConfig.isReturnGeneratedKey(), this.dbConfig, conn, insert.build(), insert.getParamValueArray()); } @Override @@ -63,36 +73,35 @@ public class AnsiSqlDialect implements Dialect { } // 批量,根据第一行数据结构生成SQL占位符 final SqlBuilder insert = SqlBuilder.of(quoteWrapper).insert(entities[0], this.dialectName()); - return StatementUtil.prepareStatementForBatch(conn, insert.build(), entities); + return StatementUtil.prepareStatementForBatch(this.dbConfig, conn, insert.build(), entities); } @Override - public PreparedStatement psForDelete(final Connection conn, final Query query) throws SQLException { + public PreparedStatement psForDelete(final Connection conn, final Query query) throws DbException { Assert.notNull(query, "query must be not null !"); final Condition[] where = query.getWhere(); if (ArrayUtil.isEmpty(where)) { // 对于无条件删除语句直接抛出异常禁止,防止误删除 - throw new SQLException("No 'WHERE' condition, we can't prepared statement for delete everything."); + throw new DbException("No 'WHERE' condition, we can't prepared statement for delete everything."); } final SqlBuilder delete = SqlBuilder.of(quoteWrapper).delete(query.getFirstTableName()).where(where); - - return StatementUtil.prepareStatement(conn, delete); + return StatementUtil.prepareStatement(false, this.dbConfig, conn, delete.build(), delete.getParamValueArray()); } @Override - public PreparedStatement psForUpdate(final Connection conn, final Entity entity, final Query query) throws SQLException { + public PreparedStatement psForUpdate(final Connection conn, final Entity entity, final Query query) throws DbException { Assert.notNull(query, "query must be not null !"); final Condition[] where = query.getWhere(); if (ArrayUtil.isEmpty(where)) { // 对于无条件地删除语句直接抛出异常禁止,防止误删除 - throw new SQLException("No 'WHERE' condition, we can't prepare statement for update everything."); + throw new DbException("No 'WHERE' condition, we can't prepare statement for update everything."); } final SqlBuilder update = SqlBuilder.of(quoteWrapper).update(entity).where(where); - return StatementUtil.prepareStatement(conn, update); + return StatementUtil.prepareStatement(false, this.dbConfig, conn, update.build(), update.getParamValueArray()); } @Override @@ -117,7 +126,7 @@ public class AnsiSqlDialect implements Dialect { if (null != page) { sqlBuilder = wrapPageSql(sqlBuilder.orderBy(page.getOrders()), page); } - return StatementUtil.prepareStatement(conn, sqlBuilder); + return StatementUtil.prepareStatement(false, this.dbConfig, conn, sqlBuilder.build(), sqlBuilder.getParamValueArray()); } /** diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/H2Dialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/H2Dialect.java index 9e555114a..06a232f3f 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/H2Dialect.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/H2Dialect.java @@ -18,6 +18,7 @@ import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.db.Entity; import org.dromara.hutool.db.Page; import org.dromara.hutool.db.StatementUtil; +import org.dromara.hutool.db.config.DbConfig; import org.dromara.hutool.db.dialect.DialectName; import org.dromara.hutool.db.sql.SqlBuilder; @@ -34,8 +35,11 @@ public class H2Dialect extends AnsiSqlDialect { /** * 构造 + * + * @param config 数据库配置 */ - public H2Dialect() { + public H2Dialect(final DbConfig config) { + super(config); // wrapper = new Wrapper('"'); } @@ -87,6 +91,6 @@ public class H2Dialect extends AnsiSqlDialect { // 更新值列表 .append(") VALUES (").append(placeHolder).append(")"); - return StatementUtil.prepareStatement(conn, builder); + return StatementUtil.prepareStatement(false, this.dbConfig, conn, builder.build(), builder.getParamValueArray()); } } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/MysqlDialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/MysqlDialect.java index fd56e0f06..602bc7fec 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/MysqlDialect.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/MysqlDialect.java @@ -16,6 +16,7 @@ import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.db.Entity; import org.dromara.hutool.db.Page; import org.dromara.hutool.db.StatementUtil; +import org.dromara.hutool.db.config.DbConfig; import org.dromara.hutool.db.dialect.DialectName; import org.dromara.hutool.db.sql.QuoteWrapper; import org.dromara.hutool.db.sql.SqlBuilder; @@ -33,8 +34,11 @@ public class MysqlDialect extends AnsiSqlDialect { /** * 构造 + * + * @param dbConfig 数据库配置 */ - public MysqlDialect() { + public MysqlDialect(final DbConfig dbConfig) { + super(dbConfig); quoteWrapper = new QuoteWrapper('`'); } @@ -100,6 +104,6 @@ public class MysqlDialect extends AnsiSqlDialect { // 主键冲突后的更新操作 .append(") ON DUPLICATE KEY UPDATE ").append(updateHolder); - return StatementUtil.prepareStatement(conn, builder); + return StatementUtil.prepareStatement(false, this.dbConfig, conn, builder.build(), builder.getParamValueArray()); } } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/OracleDialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/OracleDialect.java index de67b8612..d57de1cdb 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/OracleDialect.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/OracleDialect.java @@ -15,6 +15,7 @@ package org.dromara.hutool.db.dialect.impl; import org.dromara.hutool.core.text.StrPool; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.db.Page; +import org.dromara.hutool.db.config.DbConfig; import org.dromara.hutool.db.dialect.DialectName; import org.dromara.hutool.db.sql.SqlBuilder; @@ -43,8 +44,11 @@ public class OracleDialect extends AnsiSqlDialect { /** * 构造 + * + * @param dbConfig 数据库配置 */ - public OracleDialect() { + public OracleDialect(final DbConfig dbConfig) { + super(dbConfig); //Oracle所有字段名用双引号包围,防止字段名或表名与系统关键字冲突 //wrapper = new Wrapper('"'); } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/PhoenixDialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/PhoenixDialect.java index 0d9966ab0..76f9cc857 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/PhoenixDialect.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/PhoenixDialect.java @@ -12,13 +12,14 @@ package org.dromara.hutool.db.dialect.impl; +import org.dromara.hutool.db.DbException; import org.dromara.hutool.db.Entity; +import org.dromara.hutool.db.config.DbConfig; import org.dromara.hutool.db.dialect.DialectName; import org.dromara.hutool.db.sql.Query; import java.sql.Connection; import java.sql.PreparedStatement; -import java.sql.SQLException; /** * Phoenix数据库方言 @@ -31,13 +32,15 @@ public class PhoenixDialect extends AnsiSqlDialect { /** * 构造 + * @param dbConfig 数据库配置 */ - public PhoenixDialect() { + public PhoenixDialect(final DbConfig dbConfig) { + super(dbConfig); // wrapper = new Wrapper('"'); } @Override - public PreparedStatement psForUpdate(final Connection conn, final Entity entity, final Query query) throws SQLException { + public PreparedStatement psForUpdate(final Connection conn, final Entity entity, final Query query) throws DbException { // Phoenix的插入、更新语句是统一的,统一使用upsert into关键字 // Phoenix只支持通过主键更新操作,因此query无效,自动根据entity中的主键更新 return super.psForInsert(conn, entity); @@ -49,7 +52,7 @@ public class PhoenixDialect extends AnsiSqlDialect { } @Override - public PreparedStatement psForUpsert(final Connection conn, final Entity entity, final String... keys) throws SQLException { + public PreparedStatement psForUpsert(final Connection conn, final Entity entity, final String... keys) throws DbException { // Phoenix只支持通过主键更新操作,因此query无效,自动根据entity中的主键更新 return psForInsert(conn, entity); } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/PostgresqlDialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/PostgresqlDialect.java index 181c00b8a..78ababf6e 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/PostgresqlDialect.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/PostgresqlDialect.java @@ -18,6 +18,7 @@ import org.dromara.hutool.core.text.CharUtil; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.db.Entity; import org.dromara.hutool.db.StatementUtil; +import org.dromara.hutool.db.config.DbConfig; import org.dromara.hutool.db.dialect.DialectName; import org.dromara.hutool.db.sql.QuoteWrapper; import org.dromara.hutool.db.sql.SqlBuilder; @@ -36,8 +37,10 @@ public class PostgresqlDialect extends AnsiSqlDialect { /** * 构造 + * @param dbConfig 数据库配置 */ - public PostgresqlDialect() { + public PostgresqlDialect(final DbConfig dbConfig) { + super(dbConfig); quoteWrapper = new QuoteWrapper(CharUtil.DOUBLE_QUOTES); } @@ -89,6 +92,6 @@ public class PostgresqlDialect extends AnsiSqlDialect { // 主键冲突后的更新操作 .append(") DO UPDATE SET ").append(updateHolder); - return StatementUtil.prepareStatement(conn, builder); + return StatementUtil.prepareStatement(false, this.dbConfig, conn, builder.build(), builder.getParamValueArray()); } } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/SqlServer2012Dialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/SqlServer2012Dialect.java index b879b0195..069fc5794 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/SqlServer2012Dialect.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/SqlServer2012Dialect.java @@ -14,6 +14,7 @@ package org.dromara.hutool.db.dialect.impl; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.db.Page; +import org.dromara.hutool.db.config.DbConfig; import org.dromara.hutool.db.dialect.DialectName; import org.dromara.hutool.db.sql.SqlBuilder; import org.dromara.hutool.db.sql.QuoteWrapper; @@ -28,8 +29,10 @@ public class SqlServer2012Dialect extends AnsiSqlDialect { /** * 构造 + * @param dbConfig 数据库配置 */ - public SqlServer2012Dialect() { + public SqlServer2012Dialect(final DbConfig dbConfig) { + super(dbConfig); //双引号和中括号适用,双引号更广泛 quoteWrapper = new QuoteWrapper('"'); } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/Sqlite3Dialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/Sqlite3Dialect.java index fc9217b2f..b64f37a17 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/Sqlite3Dialect.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/Sqlite3Dialect.java @@ -12,6 +12,7 @@ package org.dromara.hutool.db.dialect.impl; +import org.dromara.hutool.db.config.DbConfig; import org.dromara.hutool.db.dialect.DialectName; import org.dromara.hutool.db.sql.QuoteWrapper; @@ -25,8 +26,11 @@ public class Sqlite3Dialect extends AnsiSqlDialect { /** * 构造 + * + * @param dbConfig 数据库配置 */ - public Sqlite3Dialect() { + public Sqlite3Dialect(final DbConfig dbConfig) { + super(dbConfig); quoteWrapper = new QuoteWrapper('[', ']'); } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/handler/NumberHandler.java b/hutool-db/src/main/java/org/dromara/hutool/db/handler/NumberHandler.java index 42efb68ef..65d21517b 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/handler/NumberHandler.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/handler/NumberHandler.java @@ -24,12 +24,9 @@ public class NumberHandler implements RsHandler{ private static final long serialVersionUID = 4081498054379705596L; /** - * 创建一个 NumberHandler对象 - * @return NumberHandler对象 + * 单例 */ - public static NumberHandler of() { - return new NumberHandler(); - } + public static final NumberHandler INSTANCE = new NumberHandler(); @Override public Number handle(final ResultSet rs) throws SQLException { diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/sql/SqlExecutor.java b/hutool-db/src/main/java/org/dromara/hutool/db/sql/SqlExecutor.java index a72a83e14..c653e63cf 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/sql/SqlExecutor.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/sql/SqlExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 looly(loolly@aliyun.com) + * Copyright (c) 2024. 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: @@ -13,38 +13,63 @@ package org.dromara.hutool.db.sql; import org.dromara.hutool.core.collection.iter.ArrayIter; -import org.dromara.hutool.core.io.IoUtil; import org.dromara.hutool.core.func.SerFunction; +import org.dromara.hutool.core.io.IoUtil; import org.dromara.hutool.db.DbException; import org.dromara.hutool.db.StatementUtil; +import org.dromara.hutool.db.config.DbConfig; import org.dromara.hutool.db.handler.RsHandler; import java.sql.*; import java.util.Map; /** - * SQL执行器,全部为静态方法,执行查询或非查询的SQL语句
- * 此方法为JDBC的简单封装,与数据库类型无关 + * SQL执行器,用于执行指定的SQL查询、更新语句。
+ * 此执行器执行原始SQL。 * - * @author loolly + * @author Looly */ public class SqlExecutor { /** - * 执行非查询语句
- * 语句包括 插入、更新、删除
- * 此方法不会关闭Connection + * 创建SqlExecutor * - * @param conn 数据库连接对象 - * @param sql SQL,使用name做为占位符,例如:name - * @param paramMap 参数Map - * @return 影响的行数 - * @throws DbException SQL执行异常 - * @since 4.0.10 + * @param config 配置 + * @param conn {@link Connection} + * @return SqlExecutor */ - public static int execute(final Connection conn, final String sql, final Map paramMap) throws DbException { - final NamedSql namedSql = new NamedSql(sql, paramMap); - return execute(conn, namedSql.getSql(), namedSql.getParamArray()); + public static SqlExecutor of(final DbConfig config, final Connection conn) { + return new SqlExecutor(config, conn); + } + + private final DbConfig config; + private final Connection conn; + + /** + * 构造 + * + * @param config 配置 + * @param conn {@link Connection} + */ + public SqlExecutor(final DbConfig config, final Connection conn) { + this.config = config; + this.conn = conn; + } + + /** + * 执行非查询语句
+ * 语句包括 插入、更新、删除
+ * 此方法不会关闭Connection + * + * @param sql SQL,使用name做为占位符,例如:name + * @param paramMap 参数Map + * @return 影响的行数 + * @throws DbException SQL执行异常 + * @since 4.0.10 + */ + public int execute(final String sql, final Map paramMap) throws DbException { + final NamedSql namedSql = new NamedSql(sql, paramMap); + return execute(namedSql.getSql(), namedSql.getParamArray()); } /** @@ -52,16 +77,15 @@ public class SqlExecutor { * 语句包括 插入、更新、删除
* 此方法不会关闭Connection * - * @param conn 数据库连接对象 * @param sql SQL * @param params 参数 * @return 影响的行数 * @throws DbException SQL执行异常 */ - public static int execute(final Connection conn, final String sql, final Object... params) throws DbException { + public int execute(final String sql, final Object... params) throws DbException { PreparedStatement ps = null; try { - ps = StatementUtil.prepareStatement(false, conn, sql, params); + ps = StatementUtil.prepareStatement(false, this.config, this.conn, sql, params); return ps.executeUpdate(); } catch (final SQLException e) { throw new DbException(e); @@ -74,16 +98,15 @@ public class SqlExecutor { * 执行调用存储过程
* 此方法不会关闭Connection * - * @param conn 数据库连接对象 * @param sql SQL * @param params 参数 * @return 如果执行后第一个结果是ResultSet,则返回true,否则返回false。 * @throws DbException SQL执行异常 */ - public static boolean call(final Connection conn, final String sql, final Object... params) throws DbException { + public boolean call(final String sql, final Object... params) throws DbException { CallableStatement call = null; try { - call = StatementUtil.prepareCall(conn, sql, params); + call = StatementUtil.prepareCall(this.config, this.conn, sql, params); return call.execute(); } catch (final SQLException e) { throw new DbException(e); @@ -96,16 +119,15 @@ public class SqlExecutor { * 执行调用存储过程
* 此方法不会关闭Connection * - * @param conn 数据库连接对象 * @param sql SQL * @param params 参数 * @return ResultSet * @throws DbException SQL执行异常 * @since 4.1.4 */ - public static ResultSet callQuery(final Connection conn, final String sql, final Object... params) throws DbException { + public ResultSet callQuery(final String sql, final Object... params) throws DbException { try { - return StatementUtil.prepareCall(conn, sql, params).executeQuery(); + return StatementUtil.prepareCall(this.config, this.conn, sql, params).executeQuery(); } catch (final SQLException e) { throw new DbException(e); } @@ -116,16 +138,15 @@ public class SqlExecutor { * 发查询语句包括 插入、更新、删除
* 此方法不会关闭Connection * - * @param conn 数据库连接对象 * @param sql SQL * @param paramMap 参数Map * @return 主键 * @throws DbException SQL执行异常 * @since 4.0.10 */ - public static Long executeForGeneratedKey(final Connection conn, final String sql, final Map paramMap) throws DbException { + public Long executeForGeneratedKey(final String sql, final Map paramMap) throws DbException { final NamedSql namedSql = new NamedSql(sql, paramMap); - return executeForGeneratedKey(conn, namedSql.getSql(), namedSql.getParamArray()); + return executeForGeneratedKey(namedSql.getSql(), namedSql.getParamArray()); } /** @@ -133,32 +154,21 @@ public class SqlExecutor { * 发查询语句包括 插入、更新、删除
* 此方法不会关闭Connection * - * @param conn 数据库连接对象 * @param sql SQL * @param params 参数 * @return 主键 * @throws DbException SQL执行异常 */ - public static Long executeForGeneratedKey(final Connection conn, final String sql, final Object... params) throws DbException { + public Long executeForGeneratedKey(final String sql, final Object... params) throws DbException { PreparedStatement ps = null; - ResultSet rs = null; try { - ps = StatementUtil.prepareStatement(true, conn, sql, params); + ps = StatementUtil.prepareStatement(true, this.config, this.conn, sql, params); ps.executeUpdate(); - rs = ps.getGeneratedKeys(); - if (rs != null && rs.next()) { - try { - return rs.getLong(1); - } catch (final SQLException e) { - // 可能会出现没有主键返回的情况 - } - } - return null; + return StatementUtil.getGeneratedKeyOfLong(ps); } catch (final SQLException e) { throw new DbException(e); } finally { IoUtil.closeQuietly(ps); - IoUtil.closeQuietly(rs); } } @@ -167,16 +177,15 @@ public class SqlExecutor { * 语句包括 插入、更新、删除
* 此方法不会关闭Connection * - * @param conn 数据库连接对象 * @param sql SQL * @param paramsBatch 批量的参数 * @return 每个SQL执行影响的行数 * @throws DbException SQL执行异常 */ - public static int[] executeBatch(final Connection conn, final String sql, final Iterable paramsBatch) throws DbException { + public int[] executeBatch(final String sql, final Iterable paramsBatch) throws DbException { PreparedStatement ps = null; try { - ps = StatementUtil.prepareStatementForBatch(conn, sql, paramsBatch); + ps = StatementUtil.prepareStatementForBatch(this.config, this.conn, sql, paramsBatch); return ps.executeBatch(); } catch (final SQLException e) { throw new DbException(e); @@ -190,14 +199,13 @@ public class SqlExecutor { * 语句包括 插入、更新、删除
* 此方法不会关闭Connection * - * @param conn 数据库连接对象 * @param sqls SQL列表 * @return 每个SQL执行影响的行数 * @throws DbException SQL执行异常 * @since 4.5.6 */ - public static int[] executeBatch(final Connection conn, final String... sqls) throws DbException { - return executeBatch(conn, new ArrayIter<>(sqls)); + public int[] executeBatch(final String... sqls) throws DbException { + return executeBatch(new ArrayIter<>(sqls)); } /** @@ -205,16 +213,15 @@ public class SqlExecutor { * 语句包括 插入、更新、删除
* 此方法不会关闭Connection * - * @param conn 数据库连接对象 * @param sqls SQL列表 * @return 每个SQL执行影响的行数 * @throws DbException SQL执行异常 * @since 4.5.6 */ - public static int[] executeBatch(final Connection conn, final Iterable sqls) throws DbException { + public int[] executeBatch(final Iterable sqls) throws DbException { Statement statement = null; try { - statement = conn.createStatement(); + statement = this.conn.createStatement(); for (final String sql : sqls) { statement.addBatch(sql); } @@ -226,12 +233,13 @@ public class SqlExecutor { } } + // region ----- query + /** * 执行查询语句,例如:select * from table where field1=:name1
* 此方法不会关闭Connection * * @param 处理结果类型 - * @param conn 数据库连接对象 * @param sql 查询语句,使用参数名占位符,例如:name * @param rsh 结果集处理对象 * @param paramMap 参数对 @@ -239,9 +247,9 @@ public class SqlExecutor { * @throws DbException SQL执行异常 * @since 4.0.10 */ - public static T query(final Connection conn, final String sql, final RsHandler rsh, final Map paramMap) throws DbException { + public T query(final String sql, final RsHandler rsh, final Map paramMap) throws DbException { final NamedSql namedSql = new NamedSql(sql, paramMap); - return query(conn, namedSql.getSql(), rsh, namedSql.getParamArray()); + return query(namedSql.getSql(), rsh, namedSql.getParamArray()); } /** @@ -249,15 +257,14 @@ public class SqlExecutor { * 此方法不会关闭Connection * * @param 处理结果类型 - * @param conn 数据库连接对象 * @param sqlBuilder SQL构建器,包含参数 * @param rsh 结果集处理对象 * @return 结果对象 * @throws DbException SQL执行异常 * @since 5.5.3 */ - public static T query(final Connection conn, final SqlBuilder sqlBuilder, final RsHandler rsh) throws DbException { - return query(conn, sqlBuilder.build(), rsh, sqlBuilder.getParamValueArray()); + public T query(final SqlBuilder sqlBuilder, final RsHandler rsh) throws DbException { + return query(sqlBuilder.build(), rsh, sqlBuilder.getParamValueArray()); } /** @@ -265,18 +272,17 @@ public class SqlExecutor { * 此方法不会关闭Connection * * @param 处理结果类型 - * @param conn 数据库连接对象 * @param sql 查询语句 * @param rsh 结果集处理对象 * @param params 参数 * @return 结果对象 * @throws DbException SQL执行异常 */ - public static T query(final Connection conn, final String sql, final RsHandler rsh, final Object... params) throws DbException { + public T query(final String sql, final RsHandler rsh, final Object... params) throws DbException { PreparedStatement ps = null; try { - ps = StatementUtil.prepareStatement(false, conn, sql, params); - return executeQuery(ps, rsh); + ps = StatementUtil.prepareStatement(false, this.config, this.conn, sql, params); + return StatementUtil.executeQuery(ps, rsh); } finally { IoUtil.closeQuietly(ps); } @@ -287,124 +293,20 @@ public class SqlExecutor { * 此方法主要用于自定义场景,如游标查询等 * * @param 处理结果类型 - * @param conn 数据库连接对象 * @param statementFunc 自定义{@link PreparedStatement}创建函数 * @param rsh 自定义结果集处理 * @return 结果 * @throws DbException SQL执行异常 * @since 5.7.17 */ - public static T query(final Connection conn, final SerFunction statementFunc, final RsHandler rsh) throws DbException { + public T query(final SerFunction statementFunc, final RsHandler rsh) throws DbException { PreparedStatement ps = null; try { ps = statementFunc.apply(conn); - return executeQuery(ps, rsh); + return StatementUtil.executeQuery(ps, rsh); } finally { IoUtil.closeQuietly(ps); } } - - // -------------------------------------------------------------------------------------- Execute With PreparedStatement - - /** - * 用于执行 INSERT、UPDATE 或 DELETE 语句以及 SQL DDL(数据定义语言)语句,例如 CREATE TABLE 和 DROP TABLE。
- * INSERT、UPDATE 或 DELETE 语句的效果是修改表中零行或多行中的一列或多列。
- * executeUpdate 的返回值是一个整数(int),指示受影响的行数(即更新计数)。
- * 对于 CREATE TABLE 或 DROP TABLE 等不操作行的语句,executeUpdate 的返回值总为零。
- * 此方法不会关闭PreparedStatement - * - * @param ps PreparedStatement对象 - * @param params 参数 - * @return 影响的行数 - * @throws DbException SQL执行异常 - */ - public static int executeUpdate(final PreparedStatement ps, final Object... params) throws DbException { - try { - StatementUtil.fillArrayParam(ps, params); - return ps.executeUpdate(); - } catch (final SQLException e) { - throw new DbException(e); - } - } - - /** - * 可用于执行任何SQL语句,返回一个boolean值,表明执行该SQL语句是否返回了ResultSet。
- * 如果执行后第一个结果是ResultSet,则返回true,否则返回false。
- * 此方法不会关闭PreparedStatement - * - * @param ps PreparedStatement对象 - * @param params 参数 - * @return 如果执行后第一个结果是ResultSet,则返回true,否则返回false。 - * @throws DbException SQL执行异常 - */ - public static boolean execute(final PreparedStatement ps, final Object... params) throws DbException { - try { - StatementUtil.fillArrayParam(ps, params); - return ps.execute(); - } catch (final SQLException e) { - throw new DbException(e); - } - } - - /** - * 执行查询语句
- * 此方法不会关闭PreparedStatement - * - * @param 处理结果类型 - * @param ps PreparedStatement - * @param rsh 结果集处理对象 - * @param params 参数 - * @return 结果对象 - * @throws DbException SQL执行异常 - */ - public static T query(final PreparedStatement ps, final RsHandler rsh, final Object... params) throws DbException { - try { - StatementUtil.fillArrayParam(ps, params); - return executeQuery(ps, rsh); - } catch (final SQLException e) { - throw new DbException(e); - } - } - - /** - * 执行查询语句并关闭PreparedStatement - * - * @param 处理结果类型 - * @param ps PreparedStatement - * @param rsh 结果集处理对象 - * @param params 参数 - * @return 结果对象 - * @throws DbException SQL执行异常 - */ - public static T queryAndClosePs(final PreparedStatement ps, final RsHandler rsh, final Object... params) throws DbException { - try { - return query(ps, rsh, params); - } finally { - IoUtil.closeQuietly(ps); - } - } - - // -------------------------------------------------------------------------------------------------------------------------------- Private method start - - /** - * 执行查询 - * - * @param ps {@link PreparedStatement} - * @param rsh 结果集处理对象 - * @return 结果对象 - * @throws DbException SQL执行异常 - * @since 4.1.13 - */ - private static T executeQuery(final PreparedStatement ps, final RsHandler rsh) throws DbException { - ResultSet rs = null; - try { - rs = ps.executeQuery(); - return rsh.handle(rs); - } catch (final SQLException e) { - throw new DbException(e); - } finally { - IoUtil.closeQuietly(rs); - } - } - // -------------------------------------------------------------------------------------------------------------------------------- Private method end + // endregion } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/sql/SqlLog.java b/hutool-db/src/main/java/org/dromara/hutool/db/sql/SqlLog.java index facb216f2..7d51db619 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/sql/SqlLog.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/sql/SqlLog.java @@ -23,11 +23,6 @@ import org.dromara.hutool.log.level.Level; */ public class SqlLog { - /** - * 单例 - */ - public static final SqlLog INSTANCE = new SqlLog(); - private final static Log log = Log.get(); /** diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java b/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java index e43b9cfcd..4601d736c 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java @@ -205,14 +205,16 @@ public class StatementBuilder implements Builder { params = namedSql.getParamArray(); } - sqlFilter.filter(this.connection, this.boundSql, this.returnGeneratedKey); + if(null != this.sqlFilter){ + this.sqlFilter.filter(this.connection, this.boundSql, this.returnGeneratedKey); + } final PreparedStatement ps; - if (returnGeneratedKey && StrUtil.startWithIgnoreCase(sql, "insert")) { + if (this.returnGeneratedKey && StrUtil.startWithIgnoreCase(sql, "insert")) { // 插入默认返回主键 - ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + ps = this.connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); } else { - ps = connection.prepareStatement(sql); + ps = this.connection.prepareStatement(sql); } return StatementWrapper.of(ps).fillArrayParam(params); diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/SqlLogFilter.java b/hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/SqlLogFilter.java index 53ec08480..2d1a818cb 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/SqlLogFilter.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/SqlLogFilter.java @@ -12,7 +12,6 @@ package org.dromara.hutool.db.sql.filter; -import org.dromara.hutool.core.lang.Console; import org.dromara.hutool.db.sql.BoundSql; import org.dromara.hutool.db.sql.SqlLog; @@ -25,20 +24,8 @@ import java.sql.Connection; */ public class SqlLogFilter implements SqlFilter { - /** - * 单例 - */ - public static final SqlLogFilter INSTANCE = new SqlLogFilter(); - private final SqlLog sqlLog; - /** - * 构造,使用默认SqlLog - */ - public SqlLogFilter() { - this(SqlLog.INSTANCE); - } - /** * 构造 *