All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dromara.hutool.db.sql.StatementUtil Maven / Gradle / Ivy

There is a newer version: 6.0.0.M3
Show newest version
/*
 * Copyright (c) 2013-2024 Hutool Team and hutool.cn
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

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.lang.Assert;
import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.stream.StreamUtil;
import org.dromara.hutool.db.DbException;
import org.dromara.hutool.db.config.DbConfig;
import org.dromara.hutool.db.handler.ResultSetUtil;
import org.dromara.hutool.db.handler.RsHandler;

import java.sql.*;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Statement和PreparedStatement工具类
 *
 * @author looly
 * @since 4.0.10
 */
public class StatementUtil {

	/**
	 * 创建{@link PreparedStatement}
	 *
	 * @param returnGeneratedKey 当为insert语句时,是否返回主键
	 * @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 DbConfig config, final Connection conn, final String sql, final Object... params) {
		return StatementBuilder.of()
			.setConnection(conn)
			.setReturnGeneratedKey(returnGeneratedKey)
			.setSqlFilter(Opt.ofNullable(config).map(DbConfig::getSqlFilters).getOrNull())
			.setSql(sql)
			.setParams(params)
			.build();
	}

	/**
	 * 创建批量操作的{@link PreparedStatement}
	 *
	 * @param config      数据库配置
	 * @param conn        数据库连接
	 * @param sql         SQL语句,使用"?"做为占位符
	 * @param paramsBatch "?"对应参数批次列表
	 * @return {@link PreparedStatement}
	 * @since 4.1.13
	 */
	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 DbConfig config, final Connection conn, final String sql,
															 final Iterable paramsBatch) {
		return StatementBuilder.of()
			.setConnection(conn)
			.setReturnGeneratedKey(false)
			.setSqlFilter(Opt.ofNullable(config).map(DbConfig::getSqlFilters).getOrNull())
			.setSql(sql)
			.setParamList(StreamUtil.of(paramsBatch).collect(Collectors.toList()))
			.buildForBatch();
	}

	/**
	 * 创建{@link CallableStatement}
	 *
	 * @param config 数据库配置
	 * @param conn   数据库连接
	 * @param sql    SQL语句,使用"?"做为占位符
	 * @param params "?"对应参数列表
	 * @return {@link CallableStatement}
	 * @throws SQLException SQL异常
	 * @since 4.1.13
	 */
	public static CallableStatement prepareCall(final DbConfig config, final Connection conn, final String sql, final Object... params) throws SQLException {
		return StatementBuilder.of()
			.setConnection(conn)
			.setSqlFilter(Opt.ofNullable(config).map(DbConfig::getSqlFilters).getOrNull())
			.setSql(sql)
			.setParams(params)
			.buildForCall();
	}

	// region ----- getGeneratedKey

	/**
	 * 获得自增键的值
* 此方法对于Oracle无效(返回null) * * @param ps PreparedStatement * @return 自增键的值,不存在返回null * @throws SQLException SQL执行异常 */ public static Long getGeneratedKeyOfLong(final Statement ps) throws SQLException { return getGeneratedKeys(ps, (rs) -> { Long generatedKey = null; if (rs != null && rs.next()) { try { generatedKey = rs.getLong(1); } catch (final SQLException e) { // 自增主键不为数字或者为Oracle的rowid,跳过 } } return generatedKey; }); } /** * 获得所有主键 * * @param ps PreparedStatement * @return 所有主键 * @throws SQLException SQL执行异常 */ public static List getGeneratedKeys(final Statement ps) throws SQLException { return getGeneratedKeys(ps, ResultSetUtil::handleRowToList); } /** * 获取主键,并使用{@link RsHandler} 处理后返回 * * @param statement {@link Statement} * @param rsHandler 主键结果集处理器 * @param 自定义主键类型 * @return 主键 * @throws SQLException SQL执行异常 * @since 5.5.3 */ public static T getGeneratedKeys(final Statement statement, final RsHandler rsHandler) throws SQLException { try (final ResultSet rs = statement.getGeneratedKeys()) { return rsHandler.handle(rs); } } // endregion /** * 获取null字段对应位置的数据类型
* 有些数据库对于null字段必须指定类型,否则会插入报错,此方法用于获取其类型,如果获取失败,使用默认的{@link Types#VARCHAR} * * @param ps {@link Statement} * @param paramIndex 参数位置,第一位从1开始 * @return 数据类型,默认{@link Types#VARCHAR} * @since 4.6.7 */ public static int getTypeOfNull(final PreparedStatement ps, final int paramIndex) { Assert.notNull(ps, "ps PreparedStatement must be not null in (getTypeOfNull)!"); return StatementWrapper.of(ps).getTypeOfNull(paramIndex); } /** * 填充SQL的参数。 * * @param ps PreparedStatement * @param params SQL参数 * @return {@link PreparedStatement} * @throws SQLException SQL执行异常 */ public static PreparedStatement fillArrayParam(final PreparedStatement ps, final Object... params) throws SQLException { return StatementWrapper.of(ps).fillArrayParam(params); } /** * 填充SQL的参数。
* 对于日期对象特殊处理:传入java.util.Date默认按照Timestamp处理 * * @param ps PreparedStatement * @param params SQL参数 * @return {@link PreparedStatement} * @throws SQLException SQL执行异常 */ public static PreparedStatement fillParams(final PreparedStatement ps, final Iterable params) throws SQLException { return fillParams(ps, params, null); } /** * 填充SQL的参数。
* 对于日期对象特殊处理:传入java.util.Date默认按照Timestamp处理 * * @param ps PreparedStatement * @param params SQL参数 * @param nullTypeCache null参数的类型缓存,避免循环中重复获取类型 * @return {@link PreparedStatement} * @throws SQLException SQL执行异常 * @since 4.6.7 */ public static PreparedStatement fillParams(final PreparedStatement ps, final Iterable params, final Map nullTypeCache) throws SQLException { return StatementWrapper.of(ps).fillParams(params, nullTypeCache); } /** * 为{@link PreparedStatement} 设置单个参数 * * @param ps {@link PreparedStatement} * @param paramIndex 参数位置,从1开始 * @param param 参数 * @throws SQLException SQL异常 * @since 4.6.7 */ 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); } } }