This commit is contained in:
Looly 2024-01-18 20:10:32 +08:00
parent e33f9c82eb
commit 430c63b9bc
22 changed files with 318 additions and 485 deletions

View File

@ -66,7 +66,7 @@ public abstract class AbstractDb<R extends AbstractDb<R>> extends DefaultConnect
this.dbConfig = ((DSWrapper) ds).getDbConfig(); this.dbConfig = ((DSWrapper) ds).getDbConfig();
this.caseInsensitive = this.dbConfig.isCaseInsensitive(); this.caseInsensitive = this.dbConfig.isCaseInsensitive();
} }
this.runner = new DialectRunner(dialect); this.runner = new DialectRunner(this.dbConfig, dialect);
} }
// ------------------------------------------------------- Constructor end // ------------------------------------------------------- Constructor end
@ -134,7 +134,7 @@ public abstract class AbstractDb<R extends AbstractDb<R>> extends DefaultConnect
* @throws DbException SQL执行异常 * @throws DbException SQL执行异常
*/ */
public Number queryNumber(final String sql, final Object... params) throws DbException { 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<R extends AbstractDb<R>> extends DefaultConnect
Connection conn = null; Connection conn = null;
try { try {
conn = this.getConnection(); conn = this.getConnection();
return SqlExecutor.query(conn, sql, rsh, params); return SqlExecutor.of(this.dbConfig, conn).query(sql, rsh, params);
} finally { } finally {
this.closeConnection(conn); this.closeConnection(conn);
} }
@ -184,7 +184,7 @@ public abstract class AbstractDb<R extends AbstractDb<R>> extends DefaultConnect
Connection conn = null; Connection conn = null;
try { try {
conn = this.getConnection(); conn = this.getConnection();
return SqlExecutor.query(conn, sql, rsh, paramMap); return SqlExecutor.of(this.dbConfig, conn).query(sql, rsh, paramMap);
} finally { } finally {
this.closeConnection(conn); this.closeConnection(conn);
} }
@ -205,7 +205,7 @@ public abstract class AbstractDb<R extends AbstractDb<R>> extends DefaultConnect
Connection conn = null; Connection conn = null;
try { try {
conn = this.getConnection(); conn = this.getConnection();
return SqlExecutor.query(conn, statementFunc, rsh); return SqlExecutor.of(this.dbConfig, conn).query(statementFunc, rsh);
} finally { } finally {
this.closeConnection(conn); this.closeConnection(conn);
} }
@ -227,7 +227,7 @@ public abstract class AbstractDb<R extends AbstractDb<R>> extends DefaultConnect
Connection conn = null; Connection conn = null;
try { try {
conn = this.getConnection(); conn = this.getConnection();
return SqlExecutor.execute(conn, sql, params); return SqlExecutor.of(this.dbConfig, conn).execute(sql, params);
} finally { } finally {
this.closeConnection(conn); this.closeConnection(conn);
} }
@ -246,7 +246,7 @@ public abstract class AbstractDb<R extends AbstractDb<R>> extends DefaultConnect
Connection conn = null; Connection conn = null;
try { try {
conn = this.getConnection(); conn = this.getConnection();
return SqlExecutor.executeForGeneratedKey(conn, sql, params); return SqlExecutor.of(this.dbConfig, conn).executeForGeneratedKey(sql, params);
} finally { } finally {
this.closeConnection(conn); this.closeConnection(conn);
} }
@ -265,7 +265,7 @@ public abstract class AbstractDb<R extends AbstractDb<R>> extends DefaultConnect
Connection conn = null; Connection conn = null;
try { try {
conn = this.getConnection(); conn = this.getConnection();
return SqlExecutor.executeBatch(conn, sql, paramsBatch); return SqlExecutor.of(this.dbConfig, conn).executeBatch(sql, paramsBatch);
} finally { } finally {
this.closeConnection(conn); this.closeConnection(conn);
} }
@ -283,7 +283,7 @@ public abstract class AbstractDb<R extends AbstractDb<R>> extends DefaultConnect
Connection conn = null; Connection conn = null;
try { try {
conn = this.getConnection(); conn = this.getConnection();
return SqlExecutor.executeBatch(conn, sqls); return SqlExecutor.of(this.dbConfig, conn).executeBatch(sqls);
} finally { } finally {
this.closeConnection(conn); this.closeConnection(conn);
} }
@ -301,7 +301,7 @@ public abstract class AbstractDb<R extends AbstractDb<R>> extends DefaultConnect
Connection conn = null; Connection conn = null;
try { try {
conn = this.getConnection(); conn = this.getConnection();
return SqlExecutor.executeBatch(conn, sqls); return SqlExecutor.of(this.dbConfig, conn).executeBatch(sqls);
} finally { } finally {
this.closeConnection(conn); this.closeConnection(conn);
} }

View File

@ -13,6 +13,7 @@
package org.dromara.hutool.db; package org.dromara.hutool.db;
import org.dromara.hutool.core.func.SerConsumer; 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.Dialect;
import org.dromara.hutool.db.dialect.DialectFactory; import org.dromara.hutool.db.dialect.DialectFactory;
import org.dromara.hutool.db.ds.DSUtil; import org.dromara.hutool.db.ds.DSUtil;
@ -33,6 +34,7 @@ import java.sql.SQLException;
public class Db extends AbstractDb<Db> { public class Db extends AbstractDb<Db> {
private static final long serialVersionUID = -3378415769645309514L; private static final long serialVersionUID = -3378415769645309514L;
// region ----- of
/** /**
* 创建Db<br> * 创建Db<br>
* 使用默认数据源自动探测数据库连接池 * 使用默认数据源自动探测数据库连接池
@ -62,7 +64,7 @@ public class Db extends AbstractDb<Db> {
* @return Db * @return Db
*/ */
public static Db of(final DataSource ds) { 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<Db> {
public static Db of(final DataSource ds, final Dialect dialect) { public static Db of(final DataSource ds, final Dialect dialect) {
return new Db(ds, dialect); return new Db(ds, dialect);
} }
// endregion
/**
* 创建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));
}
/** /**
* 构造 * 构造
@ -116,7 +88,6 @@ public class Db extends AbstractDb<Db> {
public Db(final DataSource ds, final Dialect dialect) { public Db(final DataSource ds, final Dialect dialect) {
super(ds, dialect); super(ds, dialect);
} }
// ---------------------------------------------------------------------------- Constructor end
/** /**
* 执行事务使用默认的事务级别<br> * 执行事务使用默认的事务级别<br>

View File

@ -18,12 +18,15 @@ import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.regex.PatternPool; import org.dromara.hutool.core.regex.PatternPool;
import org.dromara.hutool.core.text.StrUtil; 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.Dialect;
import org.dromara.hutool.db.dialect.DialectFactory;
import org.dromara.hutool.db.handler.NumberHandler; import org.dromara.hutool.db.handler.NumberHandler;
import org.dromara.hutool.db.handler.PageResultHandler; import org.dromara.hutool.db.handler.PageResultHandler;
import org.dromara.hutool.db.handler.RsHandler; 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.io.Serializable;
import java.sql.Connection; import java.sql.Connection;
@ -41,30 +44,19 @@ import java.util.regex.Pattern;
public class DialectRunner implements Serializable { public class DialectRunner implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private Dialect dialect; private final DbConfig config;
/** private final Dialect dialect;
* 是否大小写不敏感默认大小写不敏感
*/
protected boolean caseInsensitive = true;
/** /**
* 构造 * 构造
* *
* @param config 数据库配置
* @param dialect 方言 * @param dialect 方言
*/ */
public DialectRunner(final Dialect dialect) { public DialectRunner(final DbConfig config, final Dialect dialect) {
this.config = config;
this.dialect = dialect; this.dialect = dialect;
} }
/**
* 构造
*
* @param driverClassName 驱动类名用于识别方言
*/
public DialectRunner(final String driverClassName) {
this(DialectFactory.newDialect(driverClassName));
}
//---------------------------------------------------------------------------- CRUD start //---------------------------------------------------------------------------- CRUD start
/** /**
@ -114,10 +106,10 @@ public class DialectRunner implements Serializable {
* @since 5.7.20 * @since 5.7.20
*/ */
public int upsert(final Connection conn, final Entity record, final String... keys) throws DbException { 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 { try {
ps = getDialect().psForUpsert(conn, record, keys); ps = this.dialect.psForUpsert(conn, record, keys);
} catch (final SQLException ignore) { } catch (final DbException ignore) {
// 方言不支持使用默认 // 方言不支持使用默认
} }
if (null != ps) { if (null != ps) {
@ -264,11 +256,7 @@ public class DialectRunner implements Serializable {
public <T> T find(final Connection conn, final Query query, final RsHandler<T> rsh) throws DbException { public <T> T find(final Connection conn, final Query query, final RsHandler<T> rsh) throws DbException {
checkConn(conn); checkConn(conn);
Assert.notNull(query, "[query] is null !"); Assert.notNull(query, "[query] is null !");
try { return StatementUtil.executeQuery(dialect.psForFind(conn, query), rsh);
return SqlExecutor.queryAndClosePs(dialect.psForFind(conn, query), rsh);
} catch (final SQLException e) {
throw new DbException(e);
}
} }
/** /**
@ -281,11 +269,7 @@ public class DialectRunner implements Serializable {
*/ */
public long count(final Connection conn, final Query query) throws DbException { public long count(final Connection conn, final Query query) throws DbException {
checkConn(conn); checkConn(conn);
try { return StatementUtil.executeQuery(dialect.psForCount(conn, query), NumberHandler.INSTANCE).longValue();
return SqlExecutor.queryAndClosePs(dialect.psForCount(conn, query), new NumberHandler()).longValue();
} catch (final SQLException e) {
throw new DbException(e);
}
} }
/** /**
@ -309,13 +293,8 @@ public class DialectRunner implements Serializable {
selectSql = matcher.group(1); selectSql = matcher.group(1);
} }
try { return StatementUtil.executeQuery(dialect.psForCount(conn,
return SqlExecutor.queryAndClosePs(dialect.psForCount(conn, SqlBuilder.of(selectSql).addParams(sqlBuilder.getParamValueArray())), NumberHandler.INSTANCE).longValue();
SqlBuilder.of(selectSql).addParams(sqlBuilder.getParamValueArray())),
new NumberHandler()).longValue();
} catch (final SQLException e) {
throw new DbException(e);
}
} }
/** /**
@ -333,7 +312,7 @@ public class DialectRunner implements Serializable {
// 分页查询中总数的查询要去掉分页信息 // 分页查询中总数的查询要去掉分页信息
new PageResult<>(page, (int) count(conn, query.clone().setPage(null)))); 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); return this.find(conn, query, rsh);
} }
try { return StatementUtil.executeQuery(dialect.psForPage(conn, query), rsh);
return SqlExecutor.queryAndClosePs(dialect.psForPage(conn, query), rsh);
} catch (final SQLException e) {
throw new DbException(e);
}
} }
/** /**
@ -374,7 +349,7 @@ public class DialectRunner implements Serializable {
final PageResultHandler<Entity> entityResultHandler = PageResultHandler.of( final PageResultHandler<Entity> entityResultHandler = PageResultHandler.of(
new PageResult<>(page, (int) count(conn, sqlBuilder))); 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> T page(final Connection conn, final SqlBuilder sqlBuilder, final Page page, final RsHandler<T> rsh) throws DbException { public <T> T page(final Connection conn, final SqlBuilder sqlBuilder, final Page page, final RsHandler<T> rsh) throws DbException {
checkConn(conn); checkConn(conn);
if (null == page) { return StatementUtil.executeQuery(dialect.psForPage(conn, sqlBuilder, page), rsh);
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);
} }
//---------------------------------------------------------------------------- CRUD end //---------------------------------------------------------------------------- CRUD end
//---------------------------------------------------------------------------- Getters and Setters start
/**
* 设置是否在结果中忽略大小写<br>
* 如果忽略则在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) { public void setWrapper(final QuoteWrapper quoteWrapper) {
this.dialect.setWrapper(quoteWrapper); this.dialect.setWrapper(quoteWrapper);
} }
//---------------------------------------------------------------------------- Getters and Setters end
//---------------------------------------------------------------------------- Private method start /**
* 检查{@link Connection} 可用性
* @param conn 数据库连接
*/
private void checkConn(final Connection conn) { private void checkConn(final Connection conn) {
Assert.notNull(conn, "Connection object must be not null!"); Assert.notNull(conn, "Connection object must be not null!");
} }
//---------------------------------------------------------------------------- Private method start
} }

View File

@ -79,16 +79,6 @@ public class Session extends AbstractDb<Session> implements Closeable {
this(ds, DialectFactory.getDialect(ds)); 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<Session> implements Closeable {
// ---------------------------------------------------------------------------- Transaction method end // ---------------------------------------------------------------------------- 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 @Override
public void close() { public void close() {
closeConnection(null); closeConnection(null);

View File

@ -14,7 +14,9 @@ package org.dromara.hutool.db;
import org.dromara.hutool.core.array.ArrayUtil; import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.collection.iter.ArrayIter; 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.core.lang.Assert;
import org.dromara.hutool.db.config.DbConfig;
import org.dromara.hutool.db.handler.ResultSetUtil; import org.dromara.hutool.db.handler.ResultSetUtil;
import org.dromara.hutool.db.handler.RsHandler; import org.dromara.hutool.db.handler.RsHandler;
import org.dromara.hutool.db.sql.SqlBuilder; import org.dromara.hutool.db.sql.SqlBuilder;
@ -34,47 +36,22 @@ import java.util.Map;
*/ */
public class StatementUtil { 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} * 创建{@link PreparedStatement}
* *
* @param returnGeneratedKey 当为insert语句时是否返回主键 * @param returnGeneratedKey 当为insert语句时是否返回主键
* @param config 数据库配置
* @param conn 数据库连接 * @param conn 数据库连接
* @param sql SQL语句使用"?"做为占位符 * @param sql SQL语句使用"?"做为占位符
* @param params "?"对应参数列表或者Map表示命名参数 * @param params "?"对应参数列表或者Map表示命名参数
* @return {@link PreparedStatement} * @return {@link PreparedStatement}
* @since 5.8.19 * @since 5.8.19
*/ */
public static PreparedStatement prepareStatement(final boolean returnGeneratedKey, public static PreparedStatement prepareStatement(final boolean returnGeneratedKey, final DbConfig config, final Connection conn, final String sql, final Object... params) {
final Connection conn, final String sql, final Object... params) {
return StatementBuilder.of() return StatementBuilder.of()
.setConnection(conn) .setConnection(conn)
.setReturnGeneratedKey(returnGeneratedKey) .setReturnGeneratedKey(returnGeneratedKey)
.setSqlFilter(SqlLogFilter.INSTANCE) .setSqlFilter(config.getSqlFilters())
.setSql(sql) .setSql(sql)
.setParams(params) .setParams(params)
.build(); .build();
@ -83,31 +60,33 @@ public class StatementUtil {
/** /**
* 创建批量操作的{@link PreparedStatement} * 创建批量操作的{@link PreparedStatement}
* *
* @param config 数据库配置
* @param conn 数据库连接 * @param conn 数据库连接
* @param sql SQL语句使用"?"做为占位符 * @param sql SQL语句使用"?"做为占位符
* @param paramsBatch "?"对应参数批次列表 * @param paramsBatch "?"对应参数批次列表
* @return {@link PreparedStatement} * @return {@link PreparedStatement}
* @since 4.1.13 * @since 4.1.13
*/ */
public static PreparedStatement prepareStatementForBatch(final Connection conn, final String sql, final Object[]... paramsBatch) { public static PreparedStatement prepareStatementForBatch(final DbConfig config, final Connection conn, final String sql, final Object[]... paramsBatch) {
return prepareStatementForBatch(conn, sql, new ArrayIter<>(paramsBatch)); return prepareStatementForBatch(config, conn, sql, new ArrayIter<>(paramsBatch));
} }
/** /**
* 创建批量操作的{@link PreparedStatement} * 创建批量操作的{@link PreparedStatement}
* *
* @param config 数据库配置
* @param conn 数据库连接 * @param conn 数据库连接
* @param sql SQL语句使用"?"做为占位符 * @param sql SQL语句使用"?"做为占位符
* @param paramsBatch "?"对应参数批次列表 * @param paramsBatch "?"对应参数批次列表
* @return {@link PreparedStatement} * @return {@link PreparedStatement}
* @since 4.1.13 * @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<Object[]> paramsBatch) { final Iterable<Object[]> paramsBatch) {
return StatementBuilder.of() return StatementBuilder.of()
.setConnection(conn) .setConnection(conn)
.setReturnGeneratedKey(false) .setReturnGeneratedKey(false)
.setSqlFilter(SqlLogFilter.INSTANCE) .setSqlFilter(config.getSqlFilters())
.setSql(sql) .setSql(sql)
.setParams(ArrayUtil.ofArray(paramsBatch, Object.class)) .setParams(ArrayUtil.ofArray(paramsBatch, Object.class))
.buildForBatch(); .buildForBatch();
@ -116,6 +95,7 @@ public class StatementUtil {
/** /**
* 创建{@link CallableStatement} * 创建{@link CallableStatement}
* *
* @param config 数据库配置
* @param conn 数据库连接 * @param conn 数据库连接
* @param sql SQL语句使用"?"做为占位符 * @param sql SQL语句使用"?"做为占位符
* @param params "?"对应参数列表 * @param params "?"对应参数列表
@ -123,10 +103,10 @@ public class StatementUtil {
* @throws SQLException SQL异常 * @throws SQLException SQL异常
* @since 4.1.13 * @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() return StatementBuilder.of()
.setConnection(conn) .setConnection(conn)
.setSqlFilter(SqlLogFilter.INSTANCE) .setSqlFilter(config.getSqlFilters())
.setSql(sql) .setSql(sql)
.setParams(params) .setParams(params)
.buildForCall(); .buildForCall();
@ -250,4 +230,47 @@ public class StatementUtil {
public static void setParam(final PreparedStatement ps, final int paramIndex, final Object param) throws SQLException { public static void setParam(final PreparedStatement ps, final int paramIndex, final Object param) throws SQLException {
StatementWrapper.of(ps).setParam(paramIndex, param); StatementWrapper.of(ps).setParam(paramIndex, param);
} }
/**
* 执行查询
*
* @param ps {@link PreparedStatement}
* @param rsh 结果集处理对象
* @param <T> 结果类型
* @return 结果对象
* @throws DbException SQL执行异常
* @since 4.1.13
*/
public static <T> T executeQuery(final PreparedStatement ps, final RsHandler<T> 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);
}
}
/**
* 用于执行 INSERTUPDATE DELETE 语句以及 SQL DDL数据定义语言语句例如 CREATE TABLE DROP TABLE<br>
* INSERTUPDATE DELETE 语句的效果是修改表中零行或多行中的一列或多列<br>
* executeUpdate 的返回值是一个整数int指示受影响的行数即更新计数<br>
* 对于 CREATE TABLE DROP TABLE 等不操作行的语句executeUpdate 的返回值总为零<br>
* 此方法不会关闭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);
}
}
} }

View File

@ -12,6 +12,7 @@
package org.dromara.hutool.db.config; package org.dromara.hutool.db.config;
import org.dromara.hutool.db.Db;
import org.dromara.hutool.db.driver.DriverUtil; import org.dromara.hutool.db.driver.DriverUtil;
import org.dromara.hutool.db.sql.filter.SqlFilter; import org.dromara.hutool.db.sql.filter.SqlFilter;
import org.dromara.hutool.db.sql.filter.SqlFilterChain; import org.dromara.hutool.db.sql.filter.SqlFilterChain;
@ -280,6 +281,15 @@ public class DbConfig {
return this; return this;
} }
/**
* 获取SQL过滤器
*
* @return SQL过滤器
*/
public SqlFilterChain getSqlFilters(){
return this.sqlFilters;
}
/** /**
* 增加SQL过滤器 * 增加SQL过滤器
* *

View File

@ -18,6 +18,9 @@ import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.db.DbException; import org.dromara.hutool.db.DbException;
import org.dromara.hutool.db.driver.DriverUtil; 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.Setting;
import org.dromara.hutool.setting.props.Props; import org.dromara.hutool.setting.props.Props;
@ -61,16 +64,19 @@ public class SettingConfigParser implements ConfigParser {
} }
@Override @Override
public DbConfig parse(String group) { public DbConfig parse(final String group) {
if (group == null) { final Setting setting = this.setting;
group = StrUtil.EMPTY; final Setting subSetting = setting.getSetting(StrUtil.emptyIfNull(group));
}
final Setting subSetting = setting.getSetting(group);
if (MapUtil.isEmpty(subSetting)) { if (MapUtil.isEmpty(subSetting)) {
throw new DbException("No config for group: [{}]", group); 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); return toDbConfig(subSetting);
} }
@ -108,9 +114,7 @@ public class SettingConfigParser implements ConfigParser {
throw new DbException("No JDBC URL!"); throw new DbException("No JDBC URL!");
} }
// 移除用户可能误加入的show sql配置项 final SqlLogFilter sqlLogFilter = getSqlLogFilter(setting);
// issue#I3VW0R@Gitee
removeShowSqlParams(setting);
// 自动识别Driver // 自动识别Driver
String driver = setting.getAndRemove(DSKeys.KEY_ALIAS_DRIVER); String driver = setting.getAndRemove(DSKeys.KEY_ALIAS_DRIVER);
@ -122,7 +126,8 @@ public class SettingConfigParser implements ConfigParser {
.setUrl(url) .setUrl(url)
.setDriver(driver) .setDriver(driver)
.setUser(setting.getAndRemove(DSKeys.KEY_ALIAS_USER)) .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); final String caseInsensitive = setting.getAndRemove(DSKeys.KEY_CASE_INSENSITIVE);
@ -164,12 +169,22 @@ public class SettingConfigParser implements ConfigParser {
* 此方法用于移除用户配置在分组下的配置项目 * 此方法用于移除用户配置在分组下的配置项目
* *
* @param setting 配置项 * @param setting 配置项
* @since 5.7.2 * @return {@link SqlLogFilter}
*/ */
private static void removeShowSqlParams(final Setting setting) { private static SqlLogFilter getSqlLogFilter(final Setting setting) {
setting.remove(DSKeys.KEY_SHOW_SQL); // 初始化SQL显示
setting.remove(DSKeys.KEY_FORMAT_SQL); final boolean isShowSql = Convert.toBoolean(setting.remove(DSKeys.KEY_SHOW_SQL), false);
setting.remove(DSKeys.KEY_SHOW_PARAMS); final boolean isFormatSql = Convert.toBoolean(setting.remove(DSKeys.KEY_FORMAT_SQL), false);
setting.remove(DSKeys.KEY_SQL_LEVEL); 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);
} }
} }

View File

@ -12,6 +12,7 @@
package org.dromara.hutool.db.dialect; package org.dromara.hutool.db.dialect;
import org.dromara.hutool.db.DbException;
import org.dromara.hutool.db.Entity; import org.dromara.hutool.db.Entity;
import org.dromara.hutool.db.Page; import org.dromara.hutool.db.Page;
import org.dromara.hutool.db.sql.Order; import org.dromara.hutool.db.sql.Order;
@ -54,9 +55,9 @@ public interface Dialect extends Serializable {
* @param conn 数据库连接对象 * @param conn 数据库连接对象
* @param entity 数据实体类包含表名 * @param entity 数据实体类包含表名
* @return PreparedStatement * @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<br> * 构建用于批量插入的PreparedStatement<br>
@ -65,9 +66,9 @@ public interface Dialect extends Serializable {
* @param conn 数据库连接对象 * @param conn 数据库连接对象
* @param entities 数据实体实体的结构必须全部一致否则插入结果将不可预知 * @param entities 数据实体实体的结构必须全部一致否则插入结果将不可预知
* @return PreparedStatement * @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}<br> * 构建用于删除的{@link PreparedStatement}<br>
@ -77,9 +78,9 @@ public interface Dialect extends Serializable {
* @param conn 数据库连接对象 * @param conn 数据库连接对象
* @param query 查找条件包含表名 * @param query 查找条件包含表名
* @return PreparedStatement * @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}<br> * 构建用于更新的{@link PreparedStatement}<br>
@ -90,9 +91,9 @@ public interface Dialect extends Serializable {
* @param entity 数据实体类包含表名 * @param entity 数据实体类包含表名
* @param query 查找条件包含表名 * @param query 查找条件包含表名
* @return PreparedStatement * @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 // -------------------------------------------- Query
@ -104,9 +105,9 @@ public interface Dialect extends Serializable {
* @param conn 数据库连接对象 * @param conn 数据库连接对象
* @param query 查询条件包含表名 * @param query 查询条件包含表名
* @return PreparedStatement * @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}<br> * 构建用于分页查询的{@link PreparedStatement}<br>
@ -116,9 +117,9 @@ public interface Dialect extends Serializable {
* @param conn 数据库连接对象 * @param conn 数据库连接对象
* @param query 查询条件包含表名 * @param query 查询条件包含表名
* @return PreparedStatement * @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}<br> * 构建用于分页查询的{@link PreparedStatement}<br>
@ -129,10 +130,10 @@ public interface Dialect extends Serializable {
* @param sqlBuilder SQL构建器可以使用{@link SqlBuilder#of(CharSequence)} 包装普通SQL * @param sqlBuilder SQL构建器可以使用{@link SqlBuilder#of(CharSequence)} 包装普通SQL
* @param page 分页对象 * @param page 分页对象
* @return PreparedStatement * @return PreparedStatement
* @throws SQLException SQL执行异常 * @throws DbException SQL执行异常
* @since 5.5.3 * @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}<br> * 构建用于查询行数的{@link PreparedStatement}<br>
@ -142,9 +143,9 @@ public interface Dialect extends Serializable {
* @param conn 数据库连接对象 * @param conn 数据库连接对象
* @param query 查询条件包含表名 * @param query 查询条件包含表名
* @return PreparedStatement * @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)); return psForCount(conn, SqlBuilder.of().query(query));
} }
@ -156,10 +157,10 @@ public interface Dialect extends Serializable {
* @param conn 数据库连接对象 * @param conn 数据库连接对象
* @param sqlBuilder 查询语句应该包含分页等信息 * @param sqlBuilder 查询语句应该包含分页等信息
* @return PreparedStatement * @return PreparedStatement
* @throws SQLException SQL执行异常 * @throws DbException SQL执行异常
* @since 5.7.2 * @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 // https://gitee.com/dromara/hutool/issues/I713XQ
// 为了兼容informix等数据库此处使用count(*)而非count(1) // 为了兼容informix等数据库此处使用count(*)而非count(1)
sqlBuilder = sqlBuilder sqlBuilder = sqlBuilder
@ -177,11 +178,11 @@ public interface Dialect extends Serializable {
* @param entity 数据实体类包含表名 * @param entity 数据实体类包含表名
* @param keys 查找字段某些数据库此字段必须如H2某些数据库无需此字段如MySQL通过主键 * @param keys 查找字段某些数据库此字段必须如H2某些数据库无需此字段如MySQL通过主键
* @return PreparedStatement * @return PreparedStatement
* @throws SQLException SQL执行异常或方言数据不支持此操作 * @throws DbException SQL执行异常或方言数据不支持此操作
* @since 5.7.20 * @since 5.7.20
*/ */
default PreparedStatement psForUpsert(final Connection conn, final Entity entity, final String... keys) throws SQLException { default PreparedStatement psForUpsert(final Connection conn, final Entity entity, final String... keys) throws DbException {
throw new SQLException("Unsupported upsert operation of " + dialectName()); throw new DbException("Unsupported upsert operation of " + dialectName());
} }

View File

@ -14,19 +14,12 @@ package org.dromara.hutool.db.dialect;
import org.dromara.hutool.core.map.SafeConcurrentHashMap; import org.dromara.hutool.core.map.SafeConcurrentHashMap;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.db.driver.DriverUtil; import org.dromara.hutool.db.config.DbConfig;
import org.dromara.hutool.db.dialect.impl.AnsiSqlDialect; import org.dromara.hutool.db.dialect.impl.*;
import org.dromara.hutool.db.dialect.impl.H2Dialect; import org.dromara.hutool.db.ds.DSWrapper;
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.log.LogUtil; import org.dromara.hutool.log.LogUtil;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.sql.Connection;
import java.util.Map; import java.util.Map;
/** /**
@ -45,11 +38,11 @@ public class DialectFactory implements DriverNamePool {
* 根据驱动名创建方言<br> * 根据驱动名创建方言<br>
* 驱动名是不分区大小写完全匹配的 * 驱动名是不分区大小写完全匹配的
* *
* @param driverName JDBC驱动类名 * @param dbConfig 数据库配置
* @return 方言 * @return 方言
*/ */
public static Dialect newDialect(final String driverName) { public static Dialect newDialect(final DbConfig dbConfig) {
final Dialect dialect = internalNewDialect(driverName); final Dialect dialect = internalNewDialect(dbConfig);
LogUtil.debug("Use Dialect: [{}].", dialect.getClass().getSimpleName()); LogUtil.debug("Use Dialect: [{}].", dialect.getClass().getSimpleName());
return dialect; return dialect;
} }
@ -58,29 +51,31 @@ public class DialectFactory implements DriverNamePool {
* 根据驱动名创建方言<br> * 根据驱动名创建方言<br>
* 驱动名是不分区大小写完全匹配的 * 驱动名是不分区大小写完全匹配的
* *
* @param driverName JDBC驱动类名 * @param dbConfig 数据库配置
* @return 方言 * @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 (StrUtil.isNotBlank(driverName)) {
if (DRIVER_MYSQL.equalsIgnoreCase(driverName) || DRIVER_MYSQL_V6.equalsIgnoreCase(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)) { } else if (DRIVER_ORACLE.equalsIgnoreCase(driverName) || DRIVER_ORACLE_OLD.equalsIgnoreCase(driverName)) {
return new OracleDialect(); return new OracleDialect(dbConfig);
} else if (DRIVER_SQLLITE3.equalsIgnoreCase(driverName)) { } else if (DRIVER_SQLLITE3.equalsIgnoreCase(driverName)) {
return new Sqlite3Dialect(); return new Sqlite3Dialect(dbConfig);
} else if (DRIVER_POSTGRESQL.equalsIgnoreCase(driverName)) { } else if (DRIVER_POSTGRESQL.equalsIgnoreCase(driverName)) {
return new PostgresqlDialect(); return new PostgresqlDialect(dbConfig);
} else if (DRIVER_H2.equalsIgnoreCase(driverName)) { } else if (DRIVER_H2.equalsIgnoreCase(driverName)) {
return new H2Dialect(); return new H2Dialect(dbConfig);
} else if (DRIVER_SQLSERVER.equalsIgnoreCase(driverName)) { } else if (DRIVER_SQLSERVER.equalsIgnoreCase(driverName)) {
return new SqlServer2012Dialect(); return new SqlServer2012Dialect(dbConfig);
} else if (DRIVER_PHOENIX.equalsIgnoreCase(driverName)) { } else if (DRIVER_PHOENIX.equalsIgnoreCase(driverName)) {
return new PhoenixDialect(); return new PhoenixDialect(dbConfig);
} }
} }
// 无法识别可支持的数据库类型默认使用ANSI方言可兼容大部分SQL语句 // 无法识别可支持的数据库类型默认使用ANSI方言可兼容大部分SQL语句
return new AnsiSqlDialect(); return new AnsiSqlDialect(dbConfig);
} }
/** /**
@ -108,17 +103,6 @@ public class DialectFactory implements DriverNamePool {
* @return 方言 * @return 方言
*/ */
public static Dialect newDialect(final DataSource ds) { 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));
}
} }

View File

@ -18,6 +18,7 @@ import org.dromara.hutool.db.DbException;
import org.dromara.hutool.db.Entity; import org.dromara.hutool.db.Entity;
import org.dromara.hutool.db.Page; import org.dromara.hutool.db.Page;
import org.dromara.hutool.db.StatementUtil; 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.Dialect;
import org.dromara.hutool.db.dialect.DialectName; import org.dromara.hutool.db.dialect.DialectName;
import org.dromara.hutool.db.sql.Condition; 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.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException;
/** /**
* ANSI SQL 方言 * ANSI SQL 方言
@ -37,8 +37,18 @@ import java.sql.SQLException;
public class AnsiSqlDialect implements Dialect { public class AnsiSqlDialect implements Dialect {
private static final long serialVersionUID = 2088101129774974580L; private static final long serialVersionUID = 2088101129774974580L;
protected DbConfig dbConfig;
protected QuoteWrapper quoteWrapper = new QuoteWrapper(); protected QuoteWrapper quoteWrapper = new QuoteWrapper();
/**
* 构造
*
* @param dbConfig 数据库配置
*/
public AnsiSqlDialect(final DbConfig dbConfig) {
this.dbConfig = dbConfig;
}
@Override @Override
public QuoteWrapper getWrapper() { public QuoteWrapper getWrapper() {
return this.quoteWrapper; return this.quoteWrapper;
@ -53,7 +63,7 @@ public class AnsiSqlDialect implements Dialect {
public PreparedStatement psForInsert(final Connection conn, final Entity entity) { public PreparedStatement psForInsert(final Connection conn, final Entity entity) {
final SqlBuilder insert = SqlBuilder.of(quoteWrapper).insert(entity, this.dialectName()); 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 @Override
@ -63,36 +73,35 @@ public class AnsiSqlDialect implements Dialect {
} }
// 批量根据第一行数据结构生成SQL占位符 // 批量根据第一行数据结构生成SQL占位符
final SqlBuilder insert = SqlBuilder.of(quoteWrapper).insert(entities[0], this.dialectName()); 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 @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 !"); Assert.notNull(query, "query must be not null !");
final Condition[] where = query.getWhere(); final Condition[] where = query.getWhere();
if (ArrayUtil.isEmpty(where)) { 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); final SqlBuilder delete = SqlBuilder.of(quoteWrapper).delete(query.getFirstTableName()).where(where);
return StatementUtil.prepareStatement(false, this.dbConfig, conn, delete.build(), delete.getParamValueArray());
return StatementUtil.prepareStatement(conn, delete);
} }
@Override @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 !"); Assert.notNull(query, "query must be not null !");
final Condition[] where = query.getWhere(); final Condition[] where = query.getWhere();
if (ArrayUtil.isEmpty(where)) { 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); 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 @Override
@ -117,7 +126,7 @@ public class AnsiSqlDialect implements Dialect {
if (null != page) { if (null != page) {
sqlBuilder = wrapPageSql(sqlBuilder.orderBy(page.getOrders()), page); sqlBuilder = wrapPageSql(sqlBuilder.orderBy(page.getOrders()), page);
} }
return StatementUtil.prepareStatement(conn, sqlBuilder); return StatementUtil.prepareStatement(false, this.dbConfig, conn, sqlBuilder.build(), sqlBuilder.getParamValueArray());
} }
/** /**

View File

@ -18,6 +18,7 @@ import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.db.Entity; import org.dromara.hutool.db.Entity;
import org.dromara.hutool.db.Page; import org.dromara.hutool.db.Page;
import org.dromara.hutool.db.StatementUtil; 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.dialect.DialectName;
import org.dromara.hutool.db.sql.SqlBuilder; 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('"'); // wrapper = new Wrapper('"');
} }
@ -87,6 +91,6 @@ public class H2Dialect extends AnsiSqlDialect {
// 更新值列表 // 更新值列表
.append(") VALUES (").append(placeHolder).append(")"); .append(") VALUES (").append(placeHolder).append(")");
return StatementUtil.prepareStatement(conn, builder); return StatementUtil.prepareStatement(false, this.dbConfig, conn, builder.build(), builder.getParamValueArray());
} }
} }

View File

@ -16,6 +16,7 @@ import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.db.Entity; import org.dromara.hutool.db.Entity;
import org.dromara.hutool.db.Page; import org.dromara.hutool.db.Page;
import org.dromara.hutool.db.StatementUtil; 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.dialect.DialectName;
import org.dromara.hutool.db.sql.QuoteWrapper; import org.dromara.hutool.db.sql.QuoteWrapper;
import org.dromara.hutool.db.sql.SqlBuilder; 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('`'); quoteWrapper = new QuoteWrapper('`');
} }
@ -100,6 +104,6 @@ public class MysqlDialect extends AnsiSqlDialect {
// 主键冲突后的更新操作 // 主键冲突后的更新操作
.append(") ON DUPLICATE KEY UPDATE ").append(updateHolder); .append(") ON DUPLICATE KEY UPDATE ").append(updateHolder);
return StatementUtil.prepareStatement(conn, builder); return StatementUtil.prepareStatement(false, this.dbConfig, conn, builder.build(), builder.getParamValueArray());
} }
} }

View File

@ -15,6 +15,7 @@ package org.dromara.hutool.db.dialect.impl;
import org.dromara.hutool.core.text.StrPool; import org.dromara.hutool.core.text.StrPool;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.db.Page; 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.dialect.DialectName;
import org.dromara.hutool.db.sql.SqlBuilder; 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所有字段名用双引号包围防止字段名或表名与系统关键字冲突 //Oracle所有字段名用双引号包围防止字段名或表名与系统关键字冲突
//wrapper = new Wrapper('"'); //wrapper = new Wrapper('"');
} }

View File

@ -12,13 +12,14 @@
package org.dromara.hutool.db.dialect.impl; package org.dromara.hutool.db.dialect.impl;
import org.dromara.hutool.db.DbException;
import org.dromara.hutool.db.Entity; 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.dialect.DialectName;
import org.dromara.hutool.db.sql.Query; import org.dromara.hutool.db.sql.Query;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException;
/** /**
* Phoenix数据库方言 * Phoenix数据库方言
@ -31,13 +32,15 @@ public class PhoenixDialect extends AnsiSqlDialect {
/** /**
* 构造 * 构造
* @param dbConfig 数据库配置
*/ */
public PhoenixDialect() { public PhoenixDialect(final DbConfig dbConfig) {
super(dbConfig);
// wrapper = new Wrapper('"'); // wrapper = new Wrapper('"');
} }
@Override @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的插入更新语句是统一的统一使用upsert into关键字
// Phoenix只支持通过主键更新操作因此query无效自动根据entity中的主键更新 // Phoenix只支持通过主键更新操作因此query无效自动根据entity中的主键更新
return super.psForInsert(conn, entity); return super.psForInsert(conn, entity);
@ -49,7 +52,7 @@ public class PhoenixDialect extends AnsiSqlDialect {
} }
@Override @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中的主键更新 // Phoenix只支持通过主键更新操作因此query无效自动根据entity中的主键更新
return psForInsert(conn, entity); return psForInsert(conn, entity);
} }

View File

@ -18,6 +18,7 @@ import org.dromara.hutool.core.text.CharUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.db.Entity; import org.dromara.hutool.db.Entity;
import org.dromara.hutool.db.StatementUtil; 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.dialect.DialectName;
import org.dromara.hutool.db.sql.QuoteWrapper; import org.dromara.hutool.db.sql.QuoteWrapper;
import org.dromara.hutool.db.sql.SqlBuilder; 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); quoteWrapper = new QuoteWrapper(CharUtil.DOUBLE_QUOTES);
} }
@ -89,6 +92,6 @@ public class PostgresqlDialect extends AnsiSqlDialect {
// 主键冲突后的更新操作 // 主键冲突后的更新操作
.append(") DO UPDATE SET ").append(updateHolder); .append(") DO UPDATE SET ").append(updateHolder);
return StatementUtil.prepareStatement(conn, builder); return StatementUtil.prepareStatement(false, this.dbConfig, conn, builder.build(), builder.getParamValueArray());
} }
} }

View File

@ -14,6 +14,7 @@ package org.dromara.hutool.db.dialect.impl;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.db.Page; 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.dialect.DialectName;
import org.dromara.hutool.db.sql.SqlBuilder; import org.dromara.hutool.db.sql.SqlBuilder;
import org.dromara.hutool.db.sql.QuoteWrapper; 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('"'); quoteWrapper = new QuoteWrapper('"');
} }

View File

@ -12,6 +12,7 @@
package org.dromara.hutool.db.dialect.impl; 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.dialect.DialectName;
import org.dromara.hutool.db.sql.QuoteWrapper; 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('[', ']'); quoteWrapper = new QuoteWrapper('[', ']');
} }

View File

@ -24,12 +24,9 @@ public class NumberHandler implements RsHandler<Number>{
private static final long serialVersionUID = 4081498054379705596L; private static final long serialVersionUID = 4081498054379705596L;
/** /**
* 创建一个 NumberHandler对象 * 单例
* @return NumberHandler对象
*/ */
public static NumberHandler of() { public static final NumberHandler INSTANCE = new NumberHandler();
return new NumberHandler();
}
@Override @Override
public Number handle(final ResultSet rs) throws SQLException { public Number handle(final ResultSet rs) throws SQLException {

View File

@ -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. * Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the 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: * You may obtain a copy of Mulan PSL v2 at:
@ -13,38 +13,63 @@
package org.dromara.hutool.db.sql; package org.dromara.hutool.db.sql;
import org.dromara.hutool.core.collection.iter.ArrayIter; 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.func.SerFunction;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.db.DbException; import org.dromara.hutool.db.DbException;
import org.dromara.hutool.db.StatementUtil; import org.dromara.hutool.db.StatementUtil;
import org.dromara.hutool.db.config.DbConfig;
import org.dromara.hutool.db.handler.RsHandler; import org.dromara.hutool.db.handler.RsHandler;
import java.sql.*; import java.sql.*;
import java.util.Map; import java.util.Map;
/** /**
* SQL执行器全部为静态方法执行查询或非查询的SQL语句<br> * SQL执行器用于执行指定的SQL查询更新语句<br>
* 方法为JDBC的简单封装与数据库类型无关 * 执行器执行原始SQL
* *
* @author loolly * @author Looly
*/ */
public class SqlExecutor { public class SqlExecutor {
/** /**
* 执行非查询语句<br> * 创建SqlExecutor
* 语句包括 插入更新删除<br>
* 此方法不会关闭Connection
* *
* @param conn 数据库连接对象 * @param config 配置
* @param sql SQL使用name做为占位符例如:name * @param conn {@link Connection}
* @param paramMap 参数Map * @return SqlExecutor
* @return 影响的行数
* @throws DbException SQL执行异常
* @since 4.0.10
*/ */
public static int execute(final Connection conn, final String sql, final Map<String, Object> paramMap) throws DbException { public static SqlExecutor of(final DbConfig config, final Connection conn) {
final NamedSql namedSql = new NamedSql(sql, paramMap); return new SqlExecutor(config, conn);
return execute(conn, namedSql.getSql(), namedSql.getParamArray()); }
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;
}
/**
* 执行非查询语句<br>
* 语句包括 插入更新删除<br>
* 此方法不会关闭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<String, Object> paramMap) throws DbException {
final NamedSql namedSql = new NamedSql(sql, paramMap);
return execute(namedSql.getSql(), namedSql.getParamArray());
} }
/** /**
@ -52,16 +77,15 @@ public class SqlExecutor {
* 语句包括 插入更新删除<br> * 语句包括 插入更新删除<br>
* 此方法不会关闭Connection * 此方法不会关闭Connection
* *
* @param conn 数据库连接对象
* @param sql SQL * @param sql SQL
* @param params 参数 * @param params 参数
* @return 影响的行数 * @return 影响的行数
* @throws DbException SQL执行异常 * @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; PreparedStatement ps = null;
try { try {
ps = StatementUtil.prepareStatement(false, conn, sql, params); ps = StatementUtil.prepareStatement(false, this.config, this.conn, sql, params);
return ps.executeUpdate(); return ps.executeUpdate();
} catch (final SQLException e) { } catch (final SQLException e) {
throw new DbException(e); throw new DbException(e);
@ -74,16 +98,15 @@ public class SqlExecutor {
* 执行调用存储过程<br> * 执行调用存储过程<br>
* 此方法不会关闭Connection * 此方法不会关闭Connection
* *
* @param conn 数据库连接对象
* @param sql SQL * @param sql SQL
* @param params 参数 * @param params 参数
* @return 如果执行后第一个结果是ResultSet则返回true否则返回false * @return 如果执行后第一个结果是ResultSet则返回true否则返回false
* @throws DbException SQL执行异常 * @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; CallableStatement call = null;
try { try {
call = StatementUtil.prepareCall(conn, sql, params); call = StatementUtil.prepareCall(this.config, this.conn, sql, params);
return call.execute(); return call.execute();
} catch (final SQLException e) { } catch (final SQLException e) {
throw new DbException(e); throw new DbException(e);
@ -96,16 +119,15 @@ public class SqlExecutor {
* 执行调用存储过程<br> * 执行调用存储过程<br>
* 此方法不会关闭Connection * 此方法不会关闭Connection
* *
* @param conn 数据库连接对象
* @param sql SQL * @param sql SQL
* @param params 参数 * @param params 参数
* @return ResultSet * @return ResultSet
* @throws DbException SQL执行异常 * @throws DbException SQL执行异常
* @since 4.1.4 * @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 { try {
return StatementUtil.prepareCall(conn, sql, params).executeQuery(); return StatementUtil.prepareCall(this.config, this.conn, sql, params).executeQuery();
} catch (final SQLException e) { } catch (final SQLException e) {
throw new DbException(e); throw new DbException(e);
} }
@ -116,16 +138,15 @@ public class SqlExecutor {
* 发查询语句包括 插入更新删除<br> * 发查询语句包括 插入更新删除<br>
* 此方法不会关闭Connection * 此方法不会关闭Connection
* *
* @param conn 数据库连接对象
* @param sql SQL * @param sql SQL
* @param paramMap 参数Map * @param paramMap 参数Map
* @return 主键 * @return 主键
* @throws DbException SQL执行异常 * @throws DbException SQL执行异常
* @since 4.0.10 * @since 4.0.10
*/ */
public static Long executeForGeneratedKey(final Connection conn, final String sql, final Map<String, Object> paramMap) throws DbException { public Long executeForGeneratedKey(final String sql, final Map<String, Object> paramMap) throws DbException {
final NamedSql namedSql = new NamedSql(sql, paramMap); 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 {
* 发查询语句包括 插入更新删除<br> * 发查询语句包括 插入更新删除<br>
* 此方法不会关闭Connection * 此方法不会关闭Connection
* *
* @param conn 数据库连接对象
* @param sql SQL * @param sql SQL
* @param params 参数 * @param params 参数
* @return 主键 * @return 主键
* @throws DbException SQL执行异常 * @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; PreparedStatement ps = null;
ResultSet rs = null;
try { try {
ps = StatementUtil.prepareStatement(true, conn, sql, params); ps = StatementUtil.prepareStatement(true, this.config, this.conn, sql, params);
ps.executeUpdate(); ps.executeUpdate();
rs = ps.getGeneratedKeys(); return StatementUtil.getGeneratedKeyOfLong(ps);
if (rs != null && rs.next()) {
try {
return rs.getLong(1);
} catch (final SQLException e) {
// 可能会出现没有主键返回的情况
}
}
return null;
} catch (final SQLException e) { } catch (final SQLException e) {
throw new DbException(e); throw new DbException(e);
} finally { } finally {
IoUtil.closeQuietly(ps); IoUtil.closeQuietly(ps);
IoUtil.closeQuietly(rs);
} }
} }
@ -167,16 +177,15 @@ public class SqlExecutor {
* 语句包括 插入更新删除<br> * 语句包括 插入更新删除<br>
* 此方法不会关闭Connection * 此方法不会关闭Connection
* *
* @param conn 数据库连接对象
* @param sql SQL * @param sql SQL
* @param paramsBatch 批量的参数 * @param paramsBatch 批量的参数
* @return 每个SQL执行影响的行数 * @return 每个SQL执行影响的行数
* @throws DbException SQL执行异常 * @throws DbException SQL执行异常
*/ */
public static int[] executeBatch(final Connection conn, final String sql, final Iterable<Object[]> paramsBatch) throws DbException { public int[] executeBatch(final String sql, final Iterable<Object[]> paramsBatch) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
ps = StatementUtil.prepareStatementForBatch(conn, sql, paramsBatch); ps = StatementUtil.prepareStatementForBatch(this.config, this.conn, sql, paramsBatch);
return ps.executeBatch(); return ps.executeBatch();
} catch (final SQLException e) { } catch (final SQLException e) {
throw new DbException(e); throw new DbException(e);
@ -190,14 +199,13 @@ public class SqlExecutor {
* 语句包括 插入更新删除<br> * 语句包括 插入更新删除<br>
* 此方法不会关闭Connection * 此方法不会关闭Connection
* *
* @param conn 数据库连接对象
* @param sqls SQL列表 * @param sqls SQL列表
* @return 每个SQL执行影响的行数 * @return 每个SQL执行影响的行数
* @throws DbException SQL执行异常 * @throws DbException SQL执行异常
* @since 4.5.6 * @since 4.5.6
*/ */
public static int[] executeBatch(final Connection conn, final String... sqls) throws DbException { public int[] executeBatch(final String... sqls) throws DbException {
return executeBatch(conn, new ArrayIter<>(sqls)); return executeBatch(new ArrayIter<>(sqls));
} }
/** /**
@ -205,16 +213,15 @@ public class SqlExecutor {
* 语句包括 插入更新删除<br> * 语句包括 插入更新删除<br>
* 此方法不会关闭Connection * 此方法不会关闭Connection
* *
* @param conn 数据库连接对象
* @param sqls SQL列表 * @param sqls SQL列表
* @return 每个SQL执行影响的行数 * @return 每个SQL执行影响的行数
* @throws DbException SQL执行异常 * @throws DbException SQL执行异常
* @since 4.5.6 * @since 4.5.6
*/ */
public static int[] executeBatch(final Connection conn, final Iterable<String> sqls) throws DbException { public int[] executeBatch(final Iterable<String> sqls) throws DbException {
Statement statement = null; Statement statement = null;
try { try {
statement = conn.createStatement(); statement = this.conn.createStatement();
for (final String sql : sqls) { for (final String sql : sqls) {
statement.addBatch(sql); statement.addBatch(sql);
} }
@ -226,12 +233,13 @@ public class SqlExecutor {
} }
} }
// region ----- query
/** /**
* 执行查询语句例如select * from table where field1=:name1 <br> * 执行查询语句例如select * from table where field1=:name1 <br>
* 此方法不会关闭Connection * 此方法不会关闭Connection
* *
* @param <T> 处理结果类型 * @param <T> 处理结果类型
* @param conn 数据库连接对象
* @param sql 查询语句使用参数名占位符例如:name * @param sql 查询语句使用参数名占位符例如:name
* @param rsh 结果集处理对象 * @param rsh 结果集处理对象
* @param paramMap 参数对 * @param paramMap 参数对
@ -239,9 +247,9 @@ public class SqlExecutor {
* @throws DbException SQL执行异常 * @throws DbException SQL执行异常
* @since 4.0.10 * @since 4.0.10
*/ */
public static <T> T query(final Connection conn, final String sql, final RsHandler<T> rsh, final Map<String, Object> paramMap) throws DbException { public <T> T query(final String sql, final RsHandler<T> rsh, final Map<String, Object> paramMap) throws DbException {
final NamedSql namedSql = new NamedSql(sql, paramMap); 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 * 此方法不会关闭Connection
* *
* @param <T> 处理结果类型 * @param <T> 处理结果类型
* @param conn 数据库连接对象
* @param sqlBuilder SQL构建器包含参数 * @param sqlBuilder SQL构建器包含参数
* @param rsh 结果集处理对象 * @param rsh 结果集处理对象
* @return 结果对象 * @return 结果对象
* @throws DbException SQL执行异常 * @throws DbException SQL执行异常
* @since 5.5.3 * @since 5.5.3
*/ */
public static <T> T query(final Connection conn, final SqlBuilder sqlBuilder, final RsHandler<T> rsh) throws DbException { public <T> T query(final SqlBuilder sqlBuilder, final RsHandler<T> rsh) throws DbException {
return query(conn, sqlBuilder.build(), rsh, sqlBuilder.getParamValueArray()); return query(sqlBuilder.build(), rsh, sqlBuilder.getParamValueArray());
} }
/** /**
@ -265,18 +272,17 @@ public class SqlExecutor {
* 此方法不会关闭Connection * 此方法不会关闭Connection
* *
* @param <T> 处理结果类型 * @param <T> 处理结果类型
* @param conn 数据库连接对象
* @param sql 查询语句 * @param sql 查询语句
* @param rsh 结果集处理对象 * @param rsh 结果集处理对象
* @param params 参数 * @param params 参数
* @return 结果对象 * @return 结果对象
* @throws DbException SQL执行异常 * @throws DbException SQL执行异常
*/ */
public static <T> T query(final Connection conn, final String sql, final RsHandler<T> rsh, final Object... params) throws DbException { public <T> T query(final String sql, final RsHandler<T> rsh, final Object... params) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
ps = StatementUtil.prepareStatement(false, conn, sql, params); ps = StatementUtil.prepareStatement(false, this.config, this.conn, sql, params);
return executeQuery(ps, rsh); return StatementUtil.executeQuery(ps, rsh);
} finally { } finally {
IoUtil.closeQuietly(ps); IoUtil.closeQuietly(ps);
} }
@ -287,124 +293,20 @@ public class SqlExecutor {
* 此方法主要用于自定义场景如游标查询等 * 此方法主要用于自定义场景如游标查询等
* *
* @param <T> 处理结果类型 * @param <T> 处理结果类型
* @param conn 数据库连接对象
* @param statementFunc 自定义{@link PreparedStatement}创建函数 * @param statementFunc 自定义{@link PreparedStatement}创建函数
* @param rsh 自定义结果集处理 * @param rsh 自定义结果集处理
* @return 结果 * @return 结果
* @throws DbException SQL执行异常 * @throws DbException SQL执行异常
* @since 5.7.17 * @since 5.7.17
*/ */
public static <T> T query(final Connection conn, final SerFunction<Connection, PreparedStatement> statementFunc, final RsHandler<T> rsh) throws DbException { public <T> T query(final SerFunction<Connection, PreparedStatement> statementFunc, final RsHandler<T> rsh) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
ps = statementFunc.apply(conn); ps = statementFunc.apply(conn);
return executeQuery(ps, rsh); return StatementUtil.executeQuery(ps, rsh);
} finally { } finally {
IoUtil.closeQuietly(ps); IoUtil.closeQuietly(ps);
} }
} }
// endregion
// -------------------------------------------------------------------------------------- Execute With PreparedStatement
/**
* 用于执行 INSERTUPDATE DELETE 语句以及 SQL DDL数据定义语言语句例如 CREATE TABLE DROP TABLE<br>
* INSERTUPDATE DELETE 语句的效果是修改表中零行或多行中的一列或多列<br>
* executeUpdate 的返回值是一个整数int指示受影响的行数即更新计数<br>
* 对于 CREATE TABLE DROP TABLE 等不操作行的语句executeUpdate 的返回值总为零<br>
* 此方法不会关闭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<br>
* 如果执行后第一个结果是ResultSet则返回true否则返回false<br>
* 此方法不会关闭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);
}
}
/**
* 执行查询语句<br>
* 此方法不会关闭PreparedStatement
*
* @param <T> 处理结果类型
* @param ps PreparedStatement
* @param rsh 结果集处理对象
* @param params 参数
* @return 结果对象
* @throws DbException SQL执行异常
*/
public static <T> T query(final PreparedStatement ps, final RsHandler<T> 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 <T> 处理结果类型
* @param ps PreparedStatement
* @param rsh 结果集处理对象
* @param params 参数
* @return 结果对象
* @throws DbException SQL执行异常
*/
public static <T> T queryAndClosePs(final PreparedStatement ps, final RsHandler<T> 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> T executeQuery(final PreparedStatement ps, final RsHandler<T> 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
} }

View File

@ -23,11 +23,6 @@ import org.dromara.hutool.log.level.Level;
*/ */
public class SqlLog { public class SqlLog {
/**
* 单例
*/
public static final SqlLog INSTANCE = new SqlLog();
private final static Log log = Log.get(); private final static Log log = Log.get();
/** /**

View File

@ -205,14 +205,16 @@ public class StatementBuilder implements Builder<StatementWrapper> {
params = namedSql.getParamArray(); 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; 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 { } else {
ps = connection.prepareStatement(sql); ps = this.connection.prepareStatement(sql);
} }
return StatementWrapper.of(ps).fillArrayParam(params); return StatementWrapper.of(ps).fillArrayParam(params);

View File

@ -12,7 +12,6 @@
package org.dromara.hutool.db.sql.filter; 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.BoundSql;
import org.dromara.hutool.db.sql.SqlLog; import org.dromara.hutool.db.sql.SqlLog;
@ -25,20 +24,8 @@ import java.sql.Connection;
*/ */
public class SqlLogFilter implements SqlFilter { public class SqlLogFilter implements SqlFilter {
/**
* 单例
*/
public static final SqlLogFilter INSTANCE = new SqlLogFilter();
private final SqlLog sqlLog; private final SqlLog sqlLog;
/**
* 构造使用默认SqlLog
*/
public SqlLogFilter() {
this(SqlLog.INSTANCE);
}
/** /**
* 构造 * 构造
* *