/*
* Copyright 2022-2024 the original author or authors.
*
* 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
*
* https://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 xyz.zhouxy.jdbc;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.OptionalLong;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.sql.DataSource;
import xyz.zhouxy.plusone.commons.function.ThrowingConsumer;
import xyz.zhouxy.plusone.commons.function.ThrowingPredicate;
import xyz.zhouxy.plusone.commons.util.AssertTools;
/**
* SimpleJdbcTemplate
*
*
* 对 JDBC 的简单封装,方便数据库操作,支持事务,支持批量操作,支持自定义结果集映射
*
*
* @author ZhouXY
* @since 1.0.0
*/
public class SimpleJdbcTemplate implements JdbcOperations {
@Nonnull
private final DataSource dataSource;
public SimpleJdbcTemplate(@Nonnull DataSource dataSource) {
AssertTools.checkNotNull(dataSource);
this.dataSource = dataSource;
}
// #region - query
/** {@inheritDoc} */
@Override
public T query(String sql, Object[] params, ResultHandler resultHandler)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.query(conn, sql, params, resultHandler);
}
}
/** {@inheritDoc} */
@Override
public T query(String sql, ResultHandler resultHandler)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.query(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, resultHandler);
}
}
// #endregion
// #region - queryList
/** {@inheritDoc} */
@Override
public List queryList(String sql, Object[] params, RowMapper rowMapper)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryList(conn, sql, params, rowMapper);
}
}
/** {@inheritDoc} */
@Override
public List queryList(String sql, Object[] params, Class clazz)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryList(conn, sql, params, clazz);
}
}
/** {@inheritDoc} */
@Override
public List> queryList(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryList(conn, sql, params, RowMapper.HASH_MAP_MAPPER);
}
}
/** {@inheritDoc} */
@Override
public List queryRecordList(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryList(conn, sql, params, RowMapper.RECORD_MAPPER);
}
}
/** {@inheritDoc} */
@Override
public List queryList(String sql, RowMapper rowMapper)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryList(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
}
/** {@inheritDoc} */
@Override
public List queryList(String sql, Class clazz)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryList(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz);
}
}
/** {@inheritDoc} */
@Override
public List> queryList(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryList(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.HASH_MAP_MAPPER);
}
}
/** {@inheritDoc} */
@Override
public List queryRecordList(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryList(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.RECORD_MAPPER);
}
}
// #endregion
// #region - queryFirst
/** {@inheritDoc} */
@Override
public Optional queryFirst(String sql, Object[] params, RowMapper rowMapper)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirst(conn, sql, params, rowMapper);
}
}
/** {@inheritDoc} */
@Override
public Optional queryFirst(String sql, Object[] params, Class clazz)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirst(conn, sql, params, clazz);
}
}
/** {@inheritDoc} */
@Override
public Optional> queryFirst(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirst(conn, sql, params, RowMapper.HASH_MAP_MAPPER);
}
}
/** {@inheritDoc} */
@Override
public Optional queryFirstRecord(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirst(conn, sql, params, RowMapper.RECORD_MAPPER);
}
}
/** {@inheritDoc} */
@Override
public Optional queryFirstString(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirstString(conn, sql, params);
}
}
/** {@inheritDoc} */
@Override
public OptionalInt queryFirstInt(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirstInt(conn, sql, params);
}
}
/** {@inheritDoc} */
@Override
public OptionalLong queryFirstLong(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirstLong(conn, sql, params);
}
}
/** {@inheritDoc} */
@Override
public OptionalDouble queryFirstDouble(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirstDouble(conn, sql, params);
}
}
/** {@inheritDoc} */
@Override
public Optional queryFirstBigDecimal(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirstBigDecimal(conn, sql, params);
}
}
/** {@inheritDoc} */
@Override
public Optional queryFirst(String sql, RowMapper rowMapper)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirst(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
}
/** {@inheritDoc} */
@Override
public Optional queryFirst(String sql, Class clazz)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirst(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz);
}
}
/** {@inheritDoc} */
@Override
public Optional> queryFirst(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirst(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.HASH_MAP_MAPPER);
}
}
/** {@inheritDoc} */
@Override
public Optional queryFirstRecord(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirst(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.RECORD_MAPPER);
}
}
/** {@inheritDoc} */
@Override
public Optional queryFirstString(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirstString(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
}
/** {@inheritDoc} */
@Override
public OptionalInt queryFirstInt(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirstInt(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
}
/** {@inheritDoc} */
@Override
public OptionalLong queryFirstLong(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirstLong(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
}
/** {@inheritDoc} */
@Override
public OptionalDouble queryFirstDouble(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirstDouble(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
}
/** {@inheritDoc} */
@Override
public Optional queryFirstBigDecimal(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirstBigDecimal(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
}
// #endregion
// #region - update & batchUpdate
/** {@inheritDoc} */
@Override
public int update(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.update(conn, sql, params);
}
}
/** {@inheritDoc} */
@Override
public int update(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.update(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
}
/** {@inheritDoc} */
@Override
public List update(String sql, Object[] params, RowMapper rowMapper)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.update(conn, sql, params, rowMapper);
}
}
/** {@inheritDoc} */
@Override
public List update(String sql, RowMapper rowMapper)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.update(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
}
/** {@inheritDoc} */
@Override
public List batchUpdate(String sql, @Nullable Collection params, int batchSize)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.batchUpdate(conn, sql, params, batchSize);
}
}
/** {@inheritDoc} */
@Override
public List batchUpdateAndIgnoreException(String sql, @Nullable Collection params,
int batchSize, List exceptions)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.batchUpdateAndIgnoreException(conn, sql, params, batchSize, exceptions);
}
}
// #endregion
// #region - transaction
/**
* 执行事务。如果未发生异常,则提交事务;当有异常发生时,回滚事务
*
*
* operations 中使用 JdbcExecutor 实参进行 JDBC 操作,这些操作在一个连接中
*
*
* @param 异常类型
* @param operations 事务操作
* @throws SQLException SQL 异常
* @throws E 事务中的异常
*/
public void executeTransaction(@Nonnull final ThrowingConsumer operations)
throws SQLException, E {
AssertTools.checkNotNull(operations, "Operations can not be null.");
try (Connection conn = this.dataSource.getConnection()) {
final boolean autoCommit = conn.getAutoCommit();
try {
conn.setAutoCommit(false);
operations.accept(new JdbcExecutor(conn));
conn.commit();
}
catch (Exception e) {
conn.rollback();
throw e;
}
finally {
conn.setAutoCommit(autoCommit);
}
}
}
/**
* 执行事务。
* 如果 {@code operations} 返回 {@code true},则提交事务;
* 如果抛出异常,或返回 {@code false},则回滚事务
*
* @param 事务中的异常
* @param operations 事务操作
* @throws SQLException 数据库异常
* @throws E 事务中的异常类型
*/
public void commitIfTrue(@Nonnull final ThrowingPredicate operations)
throws SQLException, E {
AssertTools.checkNotNull(operations, "Operations can not be null.");
try (Connection conn = this.dataSource.getConnection()) {
final boolean autoCommit = conn.getAutoCommit();
try {
conn.setAutoCommit(false);
if (operations.test(new JdbcExecutor(conn))) {
conn.commit();
}
else {
conn.rollback();
}
}
catch (Exception e) {
conn.rollback();
throw e;
}
finally {
conn.setAutoCommit(autoCommit);
}
}
}
// #endregion
public static final class JdbcExecutor implements JdbcOperations {
private final Connection conn;
private JdbcExecutor(Connection conn) {
this.conn = conn;
}
// #region - query
/** {@inheritDoc} */
@Override
public T query(String sql, Object[] params, ResultHandler resultHandler)
throws SQLException {
return JdbcOperationSupport.query(this.conn, sql, params, resultHandler);
}
/** {@inheritDoc} */
@Override
public T query(String sql, ResultHandler resultHandler)
throws SQLException {
return JdbcOperationSupport.query(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, resultHandler);
}
// #endregion
// #region - queryList
/** {@inheritDoc} */
@Override
public List queryList(String sql, Object[] params, RowMapper rowMapper)
throws SQLException {
return JdbcOperationSupport.queryList(this.conn, sql, params, rowMapper);
}
/** {@inheritDoc} */
@Override
public List queryList(String sql, Object[] params, Class clazz)
throws SQLException {
return JdbcOperationSupport.queryList(this.conn, sql, params, clazz);
}
/** {@inheritDoc} */
@Override
public List> queryList(String sql, Object[] params)
throws SQLException {
return JdbcOperationSupport.queryList(this.conn, sql, params, RowMapper.HASH_MAP_MAPPER);
}
/** {@inheritDoc} */
@Override
public List queryRecordList(String sql, Object[] params)
throws SQLException {
return JdbcOperationSupport.queryList(this.conn, sql, params, RowMapper.RECORD_MAPPER);
}
/** {@inheritDoc} */
@Override
public List queryList(String sql, RowMapper rowMapper)
throws SQLException {
return JdbcOperationSupport.queryList(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
/** {@inheritDoc} */
@Override
public List queryList(String sql, Class clazz)
throws SQLException {
return JdbcOperationSupport.queryList(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz);
}
/** {@inheritDoc} */
@Override
public List> queryList(String sql)
throws SQLException {
return JdbcOperationSupport.queryList(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.HASH_MAP_MAPPER);
}
/** {@inheritDoc} */
@Override
public List queryRecordList(String sql)
throws SQLException {
return JdbcOperationSupport.queryList(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.RECORD_MAPPER);
}
// #endregion
// #region - queryFirst
/** {@inheritDoc} */
@Override
public Optional queryFirst(String sql, Object[] params, RowMapper rowMapper)
throws SQLException {
return JdbcOperationSupport.queryFirst(this.conn, sql, params, rowMapper);
}
/** {@inheritDoc} */
@Override
public Optional queryFirst(String sql, Object[] params, Class clazz)
throws SQLException {
return JdbcOperationSupport.queryFirst(this.conn, sql, params, clazz);
}
/** {@inheritDoc} */
@Override
public Optional> queryFirst(String sql, Object[] params)
throws SQLException {
return JdbcOperationSupport.queryFirst(this.conn, sql, params, RowMapper.HASH_MAP_MAPPER);
}
/** {@inheritDoc} */
@Override
public Optional queryFirstRecord(String sql, Object[] params)
throws SQLException {
return JdbcOperationSupport.queryFirst(this.conn, sql, params, RowMapper.RECORD_MAPPER);
}
/** {@inheritDoc} */
@Override
public Optional queryFirstString(String sql, Object[] params)
throws SQLException {
return JdbcOperationSupport.queryFirstString(this.conn, sql, params);
}
/** {@inheritDoc} */
@Override
public OptionalInt queryFirstInt(String sql, Object[] params)
throws SQLException {
return JdbcOperationSupport.queryFirstInt(this.conn, sql, params);
}
/** {@inheritDoc} */
@Override
public OptionalLong queryFirstLong(String sql, Object[] params)
throws SQLException {
return JdbcOperationSupport.queryFirstLong(this.conn, sql, params);
}
/** {@inheritDoc} */
@Override
public OptionalDouble queryFirstDouble(String sql, Object[] params)
throws SQLException {
return JdbcOperationSupport.queryFirstDouble(this.conn, sql, params);
}
/** {@inheritDoc} */
@Override
public Optional queryFirstBigDecimal(String sql, Object[] params)
throws SQLException {
return JdbcOperationSupport.queryFirstBigDecimal(this.conn, sql, params);
}
/** {@inheritDoc} */
@Override
public Optional queryFirst(String sql, RowMapper rowMapper)
throws SQLException {
return JdbcOperationSupport.queryFirst(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
/** {@inheritDoc} */
@Override
public Optional queryFirst(String sql, Class clazz)
throws SQLException {
return JdbcOperationSupport.queryFirst(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz);
}
/** {@inheritDoc} */
@Override
public Optional> queryFirst(String sql)
throws SQLException {
return JdbcOperationSupport.queryFirst(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.HASH_MAP_MAPPER);
}
/** {@inheritDoc} */
@Override
public Optional queryFirstRecord(String sql)
throws SQLException {
return JdbcOperationSupport.queryFirst(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.RECORD_MAPPER);
}
/** {@inheritDoc} */
@Override
public Optional queryFirstString(String sql)
throws SQLException {
return JdbcOperationSupport.queryFirstString(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
/** {@inheritDoc} */
@Override
public OptionalInt queryFirstInt(String sql)
throws SQLException {
return JdbcOperationSupport.queryFirstInt(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
/** {@inheritDoc} */
@Override
public OptionalLong queryFirstLong(String sql)
throws SQLException {
return JdbcOperationSupport.queryFirstLong(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
/** {@inheritDoc} */
@Override
public OptionalDouble queryFirstDouble(String sql)
throws SQLException {
return JdbcOperationSupport.queryFirstDouble(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
/** {@inheritDoc} */
@Override
public Optional queryFirstBigDecimal(String sql)
throws SQLException {
return JdbcOperationSupport.queryFirstBigDecimal(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
// #endregion
// #region - update & batchUpdate
/** {@inheritDoc} */
@Override
public int update(String sql, Object[] params)
throws SQLException {
return JdbcOperationSupport.update(this.conn, sql, params);
}
/** {@inheritDoc} */
@Override
public int update(String sql)
throws SQLException {
return JdbcOperationSupport.update(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
/** {@inheritDoc} */
@Override
public List update(String sql, Object[] params, RowMapper rowMapper)
throws SQLException {
return JdbcOperationSupport.update(this.conn, sql, params, rowMapper);
}
/** {@inheritDoc} */
@Override
public List update(String sql, RowMapper rowMapper)
throws SQLException {
return JdbcOperationSupport.update(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
/** {@inheritDoc} */
@Override
public List batchUpdate(String sql, @Nullable Collection params, int batchSize)
throws SQLException {
return JdbcOperationSupport.batchUpdate(this.conn, sql, params, batchSize);
}
/** {@inheritDoc} */
@Override
public List batchUpdateAndIgnoreException(String sql, @Nullable Collection params,
int batchSize, List exceptions)
throws SQLException {
return JdbcOperationSupport.batchUpdateAndIgnoreException(this.conn, sql, params, batchSize, exceptions);
}
// #endregion
}
}