diff --git a/src/main/java/xyz/zhouxy/jdbc/DbRecord.java b/src/main/java/xyz/zhouxy/jdbc/DbRecord.java index 33af73c..16edef9 100644 --- a/src/main/java/xyz/zhouxy/jdbc/DbRecord.java +++ b/src/main/java/xyz/zhouxy/jdbc/DbRecord.java @@ -16,49 +16,78 @@ package xyz.zhouxy.jdbc; +import java.util.HashMap; +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 com.google.common.annotations.Beta; -import com.google.common.base.Preconditions; + import xyz.zhouxy.plusone.commons.collection.AbstractMapWrapper; +import xyz.zhouxy.plusone.commons.util.AssertTools; import xyz.zhouxy.plusone.commons.util.OptionalTools; import xyz.zhouxy.plusone.commons.util.StringTools; -import java.util.*; - +/** + * DbRecord + * + *

+ * 封装 Map,表示一条 DB 记录 + *

+ * + * @author ZhouXY + * @since 1.0.0 + */ @Beta public class DbRecord extends AbstractMapWrapper { public DbRecord() { - super(new HashMap<>(), k -> Preconditions.checkArgument(StringTools.isNotBlank(k), "Key must has text."), null); + super(new HashMap<>(), + k -> AssertTools.checkArgument(StringTools.isNotBlank(k), "Key must has text."), + null); } public DbRecord(Map map) { - super(map, k -> Preconditions.checkArgument(StringTools.isNotBlank(k), "Key must has text."), null); + super(map, + k -> AssertTools.checkArgument(StringTools.isNotBlank(k), "Key must has text."), + null); } + /** + * 将值强转为 {@link String},并放在 {@link Optional} 中。 + * 如果 {@code key} 存在,而值不存在,则返回 {@link Optional#empty()}。 + */ public Optional getValueAsString(String key) { return this.getAndConvert(key); } - public List getValueAsList(String key) { - return this.>getAndConvert(key) - .map(l -> (l instanceof List) ? (List) l : new ArrayList<>(l)) - .orElse(Collections.emptyList()); - } - - public Set getValueAsSet(String key) { - return this.>getAndConvert(key) - .map(l -> (l instanceof Set) ? (Set) l : new HashSet<>(l)) - .orElse(Collections.emptySet()); - } - + /** + * 将值强转为 {@code int},并放在 {@link OptionalInt} 中。 + * 如果 {@code key} 存在,而值不存在,则返回 {@link OptionalInt#empty()}。 + */ + @Nonnull public OptionalInt getValueAsInt(String key) { return OptionalTools.toOptionalInt(this.getAndConvert(key)); } + /** + * 将值强转为 {@code long},并放在 {@link OptionalLong} 中。 + * 如果 {@code key} 存在,而值不存在,则返回 {@link OptionalLong#empty()}。 + */ + @Nonnull public OptionalLong getValueAsLong(String key) { return OptionalTools.toOptionalLong(this.getAndConvert(key)); } + /** + * 将值强转为 {@code double},并放在 {@link OptionalDouble} 中。 + * 如果 {@code key} 存在,而值不存在,则返回 {@link OptionalDouble#empty()}。 + */ + @Nonnull public OptionalDouble getValueAsDouble(String key) { return OptionalTools.toOptionalDouble(this.getAndConvert(key)); } diff --git a/src/main/java/xyz/zhouxy/jdbc/DefaultBeanRowMapper.java b/src/main/java/xyz/zhouxy/jdbc/DefaultBeanRowMapper.java index f0dcd6b..901ba84 100644 --- a/src/main/java/xyz/zhouxy/jdbc/DefaultBeanRowMapper.java +++ b/src/main/java/xyz/zhouxy/jdbc/DefaultBeanRowMapper.java @@ -35,9 +35,28 @@ import javax.annotation.Nullable; import com.google.common.base.CaseFormat; +import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod; + +/** + * DefaultBeanRowMapper + * + *

+ * 默认实现的将 {@link ResultSet} 转换为 Java Bean 的 {@link RowMapper}。 + *

+ * + *

+ * NOTE: 使用反射获取类型信息,也是使用反射调用无参构造器和 {@code setter} 方法。 + * 实际使用中还是建议针对目标类型自定义 {@link RowMapper}。 + *

+ * @author ZhouXY + * @since 1.0.0 + */ public class DefaultBeanRowMapper implements RowMapper { + /** Bean 的无参构造器 */ private final Constructor constructor; + + /** 列名到属性的映射 */ private final Map colPropertyMap; private DefaultBeanRowMapper(Constructor constructor, Map colPropertyMap) { @@ -45,10 +64,29 @@ public class DefaultBeanRowMapper implements RowMapper { this.colPropertyMap = colPropertyMap; } + /** + * 创建一个 DefaultBeanRowMapper + * + * @param Bean 类型 + * @param beanType Bean 类型 + * @return DefaultBeanRowMapper 对象 + * @throws SQLException 创建 DefaultBeanRowMapper 出现错误的异常时抛出 + */ + @StaticFactoryMethod(DefaultBeanRowMapper.class) public static DefaultBeanRowMapper of(Class beanType) throws SQLException { return of(beanType, null); } + /** + * 创建一个 DefaultBeanRowMapper + * + * @param Bean 类型 + * @param beanType Bean 类型 + * @param propertyColMap Bean 字段与列名的映射关系。key 是字段,value 是列名。 + * @return DefaultBeanRowMapper 对象 + * @throws SQLException 创建 DefaultBeanRowMapper 出现错误的异常时抛出 + */ + @StaticFactoryMethod(DefaultBeanRowMapper.class) public static DefaultBeanRowMapper of(Class beanType, @Nullable Map propertyColMap) throws SQLException { try { @@ -60,6 +98,7 @@ public class DefaultBeanRowMapper implements RowMapper { BeanInfo beanInfo = Introspector.getBeanInfo(beanType); PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); + // Bean 的属性名为小驼峰,对应的列名为下划线 Function keyMapper; if (propertyColMap == null || propertyColMap.isEmpty()) { keyMapper = p -> CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, p.getName()); @@ -84,13 +123,17 @@ public class DefaultBeanRowMapper implements RowMapper { } } + /** {@inheritDoc} */ @Override public T mapRow(ResultSet rs, int rowNumber) throws SQLException { try { + // 调用无参构造器创建实例 T newInstance = this.constructor.newInstance(); ResultSetMetaData metaData = rs.getMetaData(); + // 遍历结果的每一列 for (int i = 1; i <= metaData.getColumnCount(); i++) { String colName = metaData.getColumnName(i); + // 获取查询结果列名对应的属性,调用 setter PropertyDescriptor propertyDescriptor = this.colPropertyMap.get(colName); if (propertyDescriptor != null) { Method setter = propertyDescriptor.getWriteMethod(); diff --git a/src/main/java/xyz/zhouxy/jdbc/ParamBuilder.java b/src/main/java/xyz/zhouxy/jdbc/ParamBuilder.java index 3dccdce..5bf9af0 100644 --- a/src/main/java/xyz/zhouxy/jdbc/ParamBuilder.java +++ b/src/main/java/xyz/zhouxy/jdbc/ParamBuilder.java @@ -27,12 +27,21 @@ import java.util.OptionalLong; import java.util.function.Function; import java.util.stream.Collectors; -import com.google.common.base.Preconditions; - import xyz.zhouxy.plusone.commons.collection.CollectionTools; import xyz.zhouxy.plusone.commons.util.ArrayTools; +import xyz.zhouxy.plusone.commons.util.AssertTools; import xyz.zhouxy.plusone.commons.util.OptionalTools; +/** + * ParamBuilder + * + *

+ * JDBC 参数构造器,将数据转换为 {@code Object[]} 类型,以传给 {@link PreparedStatement} + *

+ * + * @author ZhouXY + * @since 1.0.0 + */ public class ParamBuilder { public static final Object[] EMPTY_OBJECT_ARRAY = {}; @@ -60,8 +69,8 @@ public class ParamBuilder { } public static List buildBatchParams(final Collection c, final Function func) { - Preconditions.checkNotNull(c, "The collection can not be null."); - Preconditions.checkNotNull(func, "The func can not be null."); + AssertTools.checkNotNull(c, "The collection can not be null."); + AssertTools.checkNotNull(func, "The func can not be null."); if (CollectionTools.isEmpty(c)) { return Collections.emptyList(); } diff --git a/src/main/java/xyz/zhouxy/jdbc/ResultHandler.java b/src/main/java/xyz/zhouxy/jdbc/ResultHandler.java index b15019e..ff64392 100644 --- a/src/main/java/xyz/zhouxy/jdbc/ResultHandler.java +++ b/src/main/java/xyz/zhouxy/jdbc/ResultHandler.java @@ -19,7 +19,21 @@ package xyz.zhouxy.jdbc; import java.sql.ResultSet; import java.sql.SQLException; +/** + * ResultHandler + * + *

+ * 处理 {@link ResultSet} + *

+ * + * @author ZhouXY + * @since 1.0.0 + */ @FunctionalInterface public interface ResultHandler { + + /** + * 将 {@link ResultSet} 转换为指定类型的对象 + */ T handle(ResultSet resultSet) throws SQLException; } diff --git a/src/main/java/xyz/zhouxy/jdbc/RowMapper.java b/src/main/java/xyz/zhouxy/jdbc/RowMapper.java index 404013f..e7b6b33 100644 --- a/src/main/java/xyz/zhouxy/jdbc/RowMapper.java +++ b/src/main/java/xyz/zhouxy/jdbc/RowMapper.java @@ -22,10 +22,21 @@ import java.sql.SQLException; import java.util.HashMap; import java.util.Map; +/** + * RowMapper + * + *

+ * {@link ResultSet} 中每一行数据的处理逻辑。 + *

+ * + * @author ZhouXY + * @since 1.0.0 + */ @FunctionalInterface public interface RowMapper { T mapRow(ResultSet rs, int rowNumber) throws SQLException; + /** 每一行数据转换为 {@link HashMap} */ public static final RowMapper> HASH_MAP_MAPPER = (rs, rowNumber) -> { Map result = new HashMap<>(); ResultSetMetaData metaData = rs.getMetaData(); @@ -37,13 +48,16 @@ public interface RowMapper { return result; }; + /** 每一行数据转换为 {@link DbRecord} */ public static final RowMapper RECORD_MAPPER = (rs, rowNumber) -> new DbRecord(HASH_MAP_MAPPER.mapRow(rs, rowNumber)); + /** 默认实现的将 {@link ResultSet} 转换为 Java Bean 的 {@link RowMapper}。 */ public static RowMapper beanRowMapper(Class beanType) throws SQLException { return DefaultBeanRowMapper.of(beanType); } + /** 默认实现的将 {@link ResultSet} 转换为 Java Bean 的 {@link RowMapper}。 */ public static RowMapper beanRowMapper(Class beanType, Map propertyColMap) throws SQLException { return DefaultBeanRowMapper.of(beanType, propertyColMap); diff --git a/src/main/java/xyz/zhouxy/jdbc/SimpleJdbcTemplate.java b/src/main/java/xyz/zhouxy/jdbc/SimpleJdbcTemplate.java index fc44d6c..c7beca8 100644 --- a/src/main/java/xyz/zhouxy/jdbc/SimpleJdbcTemplate.java +++ b/src/main/java/xyz/zhouxy/jdbc/SimpleJdbcTemplate.java @@ -39,9 +39,21 @@ import javax.sql.DataSource; import com.google.common.collect.Lists; import xyz.zhouxy.plusone.commons.collection.CollectionTools; +import xyz.zhouxy.plusone.commons.function.ThrowingConsumer; +import xyz.zhouxy.plusone.commons.function.ThrowingPredicate; import xyz.zhouxy.plusone.commons.util.AssertTools; import xyz.zhouxy.plusone.commons.util.OptionalTools; +/** + * SimpleJdbcTemplate + * + *

+ * 对 JDBC 的简单封装,方便数据库操作,支持事务,支持批量操作,支持自定义结果集映射 + *

+ * + * @author ZhouXY + * @since 1.0.0 + */ public class SimpleJdbcTemplate { @Nonnull @@ -54,6 +66,13 @@ public class SimpleJdbcTemplate { // #region - query + /** + * 执行查询,并按照自定义处理逻辑对结果进行处理,将结果转换为指定类型并返回 + * + * @param sql SQL + * @param params 参数 + * @param resultHandler 结果处理器,用于处理 {@link ResultSet} + */ public T query(String sql, Object[] params, ResultHandler resultHandler) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -61,6 +80,12 @@ public class SimpleJdbcTemplate { } } + /** + * 执行查询,并按照自定义处理逻辑对结果进行处理,将结果转换为指定类型并返回 + * + * @param sql SQL + * @param resultHandler 结果处理器,用于处理 {@link ResultSet} + */ public T query(String sql, ResultHandler resultHandler) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -72,6 +97,13 @@ public class SimpleJdbcTemplate { // #region - queryList + /** + * 执行查询,将查询结果的每一行数据按照指定逻辑进行处理,返回结果列表 + * + * @param sql SQL + * @param params 参数 + * @param rowMapper {@link ResultSet} 中每一行的数据的处理逻辑 + */ public List queryList(String sql, Object[] params, RowMapper rowMapper) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -79,6 +111,13 @@ public class SimpleJdbcTemplate { } } + /** + * 执行查询,返回结果映射为指定的类型。当结果为单列时使用 + * + * @param sql SQL + * @param params 参数 + * @param clazz 将结果映射为指定的类型 + */ public List queryList(String sql, Object[] params, Class clazz) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -86,6 +125,12 @@ public class SimpleJdbcTemplate { } } + /** + * 执行查询,每一行数据映射为 {@code Map},返回结果列表 + * + * @param sql SQL + * @param params 参数列表 + */ public List> queryList(String sql, Object[] params) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -93,6 +138,12 @@ public class SimpleJdbcTemplate { } } + /** + * 执行查询,每一行数据映射为 {@link DbRecord},返回结果列表 + * + * @param sql SQL + * @param params 参数列表 + */ public List queryRecordList(String sql, Object[] params) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -100,6 +151,12 @@ public class SimpleJdbcTemplate { } } + /** + * 执行查询,将查询结果的每一行数据按照指定逻辑进行处理,返回结果列表 + * + * @param sql SQL + * @param rowMapper {@link ResultSet} 中每一行的数据的处理逻辑 + */ public List queryList(String sql, RowMapper rowMapper) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -107,6 +164,12 @@ public class SimpleJdbcTemplate { } } + /** + * 执行查询,返回结果映射为指定的类型。当结果为单列时使用 + * + * @param sql SQL + * @param clazz 将结果映射为指定的类型 + */ public List queryList(String sql, Class clazz) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -114,6 +177,11 @@ public class SimpleJdbcTemplate { } } + /** + * 执行查询,每一行数据映射为 {@code Map},返回结果列表 + * + * @param sql SQL + */ public List> queryList(String sql) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -121,6 +189,11 @@ public class SimpleJdbcTemplate { } } + /** + * 执行查询,每一行数据映射为 {@link DbRecord},返回结果列表 + * + * @param sql SQL + */ public List queryRecordList(String sql) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -132,6 +205,13 @@ public class SimpleJdbcTemplate { // #region - queryFirst + /** + * 执行查询,将查询结果的第一行数据按照指定逻辑进行处理,返回 {@link Optional} + * + * @param sql SQL + * @param params 参数 + * @param rowMapper {@link ResultSet} 中每一行的数据的处理逻辑 + */ public Optional queryFirst(String sql, Object[] params, RowMapper rowMapper) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -139,6 +219,14 @@ public class SimpleJdbcTemplate { } } + /** + * 查询第一行第一列,并转换为指定类型 + * + * @param 目标类型 + * @param sql SQL + * @param params 参数 + * @param clazz 目标类型 + */ public Optional queryFirst(String sql, Object[] params, Class clazz) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -146,6 +234,12 @@ public class SimpleJdbcTemplate { } } + /** + * 执行查询,将第一行数据转为 Map + * + * @param sql SQL + * @param params 参数 + */ public Optional> queryFirst(String sql, Object[] params) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -153,6 +247,12 @@ public class SimpleJdbcTemplate { } } + /** + * 执行查询,将第一行数据转为 DbRecord + * + * @param sql SQL + * @param params 参数 + */ public Optional queryFirstRecord(String sql, Object[] params) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -160,6 +260,12 @@ public class SimpleJdbcTemplate { } } + /** + * 查询第一行第一列,并转换为字符串 + * + * @param sql SQL + * @param params 参数 + */ public Optional queryFirstString(String sql, Object[] params) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -167,6 +273,12 @@ public class SimpleJdbcTemplate { } } + /** + * 查询第一行第一列,并转换为整数值 + * + * @param sql SQL + * @param params 参数 + */ public OptionalInt queryFirstInt(String sql, Object[] params) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -174,6 +286,12 @@ public class SimpleJdbcTemplate { } } + /** + * 查询第一行第一列,并转换为长整型 + * + * @param sql SQL + * @param params 参数 + */ public OptionalLong queryFirstLong(String sql, Object[] params) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -181,6 +299,12 @@ public class SimpleJdbcTemplate { } } + /** + * 查询第一行第一列,并转换为双精度浮点型 + * + * @param sql SQL + * @param params 参数 + */ public OptionalDouble queryFirstDouble(String sql, Object[] params) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -188,6 +312,12 @@ public class SimpleJdbcTemplate { } } + /** + * 查询第一行第一列,并转换为 {@link BigDecimal} + * + * @param sql SQL + * @param params 参数 + */ public Optional queryFirstBigDecimal(String sql, Object[] params) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -195,6 +325,12 @@ public class SimpleJdbcTemplate { } } + /** + * 执行查询,将查询结果的第一行数据按照指定逻辑进行处理,返回 {@link Optional} + * + * @param sql SQL + * @param rowMapper {@link ResultSet} 中每一行的数据的处理逻辑 + */ public Optional queryFirst(String sql, RowMapper rowMapper) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -202,6 +338,13 @@ public class SimpleJdbcTemplate { } } + /** + * 查询第一行第一列,并转换为指定类型 + * + * @param 目标类型 + * @param sql SQL + * @param clazz 目标类型 + */ public Optional queryFirst(String sql, Class clazz) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -209,6 +352,11 @@ public class SimpleJdbcTemplate { } } + /** + * 执行查询,将第一行数据转为 Map + * + * @param sql SQL + */ public Optional> queryFirst(String sql) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -216,6 +364,11 @@ public class SimpleJdbcTemplate { } } + /** + * 执行查询,将第一行数据转为 DbRecord + * + * @param sql SQL + */ public Optional queryFirstRecord(String sql) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -223,6 +376,11 @@ public class SimpleJdbcTemplate { } } + /** + * 查询第一行第一列,并转换为字符串 + * + * @param sql SQL + */ public Optional queryFirstString(String sql) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -230,6 +388,11 @@ public class SimpleJdbcTemplate { } } + /** + * 查询第一行第一列,并转换为整数值 + * + * @param sql SQL + */ public OptionalInt queryFirstInt(String sql) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -237,6 +400,11 @@ public class SimpleJdbcTemplate { } } + /** + * 查询第一行第一列,并转换为长整型 + * + * @param sql SQL + */ public OptionalLong queryFirstLong(String sql) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -244,6 +412,11 @@ public class SimpleJdbcTemplate { } } + /** + * 查询第一行第一列,并转换为双精度浮点型 + * + * @param sql SQL + */ public OptionalDouble queryFirstDouble(String sql) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -251,6 +424,11 @@ public class SimpleJdbcTemplate { } } + /** + * 查询第一行第一列,并转换为 {@link BigDecimal} + * + * @param sql SQL + */ public Optional queryFirstBigDecimal(String sql) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -262,6 +440,13 @@ public class SimpleJdbcTemplate { // #region - update & batchUpdate + /** + * 执行更新操作 + * + * @param sql 要执行的 SQL + * @param params 参数 + * @return 更新记录数 + */ public int update(String sql, Object[] params) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -269,6 +454,12 @@ public class SimpleJdbcTemplate { } } + /** + * 执行更新操作 + * + * @param sql 要执行的 SQL + * @return 更新记录数 + */ public int update(String sql) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -277,13 +468,13 @@ public class SimpleJdbcTemplate { } /** - * 执行 SQL 并更新后的数据 - * - * @param sql 要执行的 SQL 语句 + * 执行 SQL 并返回生成的 keys + * + * @param sql 要执行的 SQL * @param params 参数 - * @param rowMapper 结果映射规则 - * - * @return 更新的数据 + * @param rowMapper 行数据映射逻辑 + * + * @return generated keys * @throws SQLException 执行 SQL 遇到异常情况将抛出 */ public List update(String sql, Object[] params, RowMapper rowMapper) @@ -294,13 +485,12 @@ public class SimpleJdbcTemplate { } /** - * 执行 SQL 并更新后的数据 - * - * @param sql 要执行的 SQL 语句 - * @param params 参数 - * @param rowMapper 结果映射规则 - * - * @return 更新的数据 + * 执行 SQL 并返回生成的 keys + * + * @param sql 要执行的 SQL + * @param rowMapper 行数据映射逻辑 + * + * @return generated keys * @throws SQLException 执行 SQL 遇到异常情况将抛出 */ public List update(String sql, RowMapper rowMapper) @@ -310,6 +500,13 @@ public class SimpleJdbcTemplate { } } + /** + * 执行批量更新,批量更新数据,返回每条记录更新的行数 + * + * @param sql SQL 语句 + * @param params 参数列表 + * @param batchSize 每次批量更新的数据量 + */ public List batchUpdate(String sql, @Nullable Collection params, int batchSize) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { @@ -317,6 +514,14 @@ public class SimpleJdbcTemplate { } } + /** + * 批量更新,返回更新成功的记录行数。发生异常时不中断操作,将异常存入 {@code exceptions} 中 + * + * @param sql sql语句 + * @param params 参数列表 + * @param batchSize 每次批量更新的数据量 + * @param exceptions 异常列表,用于记录异常信息 + */ public List batchUpdateAndIgnoreException(String sql, @Nullable Collection params, int batchSize, List exceptions) throws SQLException { @@ -329,14 +534,26 @@ public class SimpleJdbcTemplate { // #region - transaction - public void executeTransaction(@Nonnull final DbOperations operations) + /** + * 执行事务。如果未发生异常,则提交事务;当有异常发生时,回滚事务 + * + *

+ * 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.execute(new JdbcExecutor(conn)); + operations.accept(new JdbcExecutor(conn)); conn.commit(); } catch (Exception e) { @@ -349,7 +566,17 @@ public class SimpleJdbcTemplate { } } - public void commitIfTrue(@Nonnull final PredicateWithThrowable operations) + /** + * 执行事务。 + * 如果 {@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()) { @@ -373,16 +600,6 @@ public class SimpleJdbcTemplate { } } - @FunctionalInterface - public interface DbOperations { - void execute(JdbcExecutor jdbcExecutor) throws E; - } - - @FunctionalInterface - public interface PredicateWithThrowable { - boolean test(JdbcExecutor jdbcExecutor) throws E; - } - // #endregion public static final class JdbcExecutor { @@ -395,55 +612,116 @@ public class SimpleJdbcTemplate { // #region - query - public T query(String sql, Object[] params, ResultHandler resulthHandler) + /** + * 执行查询,并按照自定义处理逻辑对结果进行处理,将结果转换为指定类型并返回 + * + * @param sql SQL + * @param params 参数 + * @param resultHandler 结果处理器,用于处理 {@link ResultSet} + */ + public T query(String sql, Object[] params, ResultHandler resultHandler) throws SQLException { - return JdbcExecutor.query(this.conn, sql, params, resulthHandler); + return JdbcExecutor.query(this.conn, sql, params, resultHandler); } - public T query(String sql, ResultHandler resulthHandler) + /** + * 执行查询,并按照自定义处理逻辑对结果进行处理,将结果转换为指定类型并返回 + * + * @param sql SQL + * @param resultHandler 结果处理器,用于处理 {@link ResultSet} + */ + public T query(String sql, ResultHandler resultHandler) throws SQLException { - return JdbcExecutor.query(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, resulthHandler); + return JdbcExecutor.query(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, resultHandler); } // #endregion // #region - queryList + /** + * 执行查询,将查询结果的每一行数据按照指定逻辑进行处理,返回结果列表 + * + * @param sql SQL + * @param params 参数 + * @param rowMapper {@link ResultSet} 中每一行的数据的处理逻辑 + */ public List queryList(String sql, Object[] params, RowMapper rowMapper) throws SQLException { return JdbcExecutor.queryList(this.conn, sql, params, rowMapper); } + /** + * 执行查询,返回结果映射为指定的类型。当结果为单列时使用 + * + * @param sql SQL + * @param params 参数 + * @param clazz 将结果映射为指定的类型 + */ public List queryList(String sql, Object[] params, Class clazz) throws SQLException { return JdbcExecutor.queryList(this.conn, sql, params, clazz); } + /** + * 执行查询,每一行数据映射为 {@code Map},返回结果列表 + * + * @param sql SQL + * @param params 参数列表 + */ public List> queryList(String sql, Object[] params) throws SQLException { return JdbcExecutor.queryList(this.conn, sql, params, RowMapper.HASH_MAP_MAPPER); } + /** + * 执行查询,每一行数据映射为 {@link DbRecord},返回结果列表 + * + * @param sql SQL + * @param params 参数列表 + */ public List queryRecordList(String sql, Object[] params) throws SQLException { return JdbcExecutor.queryList(this.conn, sql, params, RowMapper.RECORD_MAPPER); } + /** + * 执行查询,将查询结果的每一行数据按照指定逻辑进行处理,返回结果列表 + * + * @param sql SQL + * @param rowMapper {@link ResultSet} 中每一行的数据的处理逻辑 + */ public List queryList(String sql, RowMapper rowMapper) throws SQLException { return JdbcExecutor.queryList(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper); } + /** + * 执行查询,返回结果映射为指定的类型。当结果为单列时使用 + * + * @param sql SQL + * @param clazz 将结果映射为指定的类型 + */ public List queryList(String sql, Class clazz) throws SQLException { return JdbcExecutor.queryList(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz); } + /** + * 执行查询,每一行数据映射为 {@code Map},返回结果列表 + * + * @param sql SQL + */ public List> queryList(String sql) throws SQLException { return JdbcExecutor.queryList(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.HASH_MAP_MAPPER); } + /** + * 执行查询,每一行数据映射为 {@link DbRecord},返回结果列表 + * + * @param sql SQL + */ public List queryRecordList(String sql) throws SQLException { return JdbcExecutor.queryList(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.RECORD_MAPPER); @@ -453,91 +731,196 @@ public class SimpleJdbcTemplate { // #region - queryFirst + /** + * 执行查询,将查询结果的第一行数据按照指定逻辑进行处理,返回 {@link Optional} + * + * @param sql SQL + * @param params 参数 + * @param rowMapper {@link ResultSet} 中每一行的数据的处理逻辑 + */ public Optional queryFirst(String sql, Object[] params, RowMapper rowMapper) throws SQLException { return JdbcExecutor.queryFirst(this.conn, sql, params, rowMapper); } + /** + * 查询第一行第一列,并转换为指定类型 + * + * @param 目标类型 + * @param sql SQL + * @param params 参数 + * @param clazz 目标类型 + */ public Optional queryFirst(String sql, Object[] params, Class clazz) throws SQLException { return JdbcExecutor.queryFirst(this.conn, sql, params, clazz); } + /** + * 执行查询,将第一行数据转为 Map + * + * @param sql SQL + * @param params 参数 + */ public Optional> queryFirst(String sql, Object[] params) throws SQLException { return JdbcExecutor.queryFirst(this.conn, sql, params, RowMapper.HASH_MAP_MAPPER); } + /** + * 执行查询,将第一行数据转为 DbRecord + * + * @param sql SQL + * @param params 参数 + */ public Optional queryFirstRecord(String sql, Object[] params) throws SQLException { return JdbcExecutor.queryFirst(this.conn, sql, params, RowMapper.RECORD_MAPPER); } + /** + * 查询第一行第一列,并转换为字符串 + * + * @param sql SQL + * @param params 参数 + */ public Optional queryFirstString(String sql, Object[] params) throws SQLException { return JdbcExecutor.queryFirstString(this.conn, sql, params); } + /** + * 查询第一行第一列,并转换为整数值 + * + * @param sql SQL + * @param params 参数 + */ public OptionalInt queryFirstInt(String sql, Object[] params) throws SQLException { return JdbcExecutor.queryFirstInt(this.conn, sql, params); } + /** + * 查询第一行第一列,并转换为长整型 + * + * @param sql SQL + * @param params 参数 + */ public OptionalLong queryFirstLong(String sql, Object[] params) throws SQLException { return JdbcExecutor.queryFirstLong(this.conn, sql, params); } + /** + * 查询第一行第一列,并转换为双精度浮点型 + * + * @param sql SQL + * @param params 参数 + */ public OptionalDouble queryFirstDouble(String sql, Object[] params) throws SQLException { return JdbcExecutor.queryFirstDouble(this.conn, sql, params); } + /** + * 查询第一行第一列,并转换为 {@link BigDecimal} + * + * @param sql SQL + * @param params 参数 + */ public Optional queryFirstBigDecimal(String sql, Object[] params) throws SQLException { return JdbcExecutor.queryFirstBigDecimal(this.conn, sql, params); } + /** + * 执行查询,将查询结果的第一行数据按照指定逻辑进行处理,返回 {@link Optional} + * + * @param sql SQL + * @param rowMapper {@link ResultSet} 中每一行的数据的处理逻辑 + */ public Optional queryFirst(String sql, RowMapper rowMapper) throws SQLException { return JdbcExecutor.queryFirst(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper); } + /** + * 查询第一行第一列,并转换为指定类型 + * + * @param 目标类型 + * @param sql SQL + * @param clazz 目标类型 + */ public Optional queryFirst(String sql, Class clazz) throws SQLException { return JdbcExecutor.queryFirst(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz); } + /** + * 执行查询,将第一行数据转为 Map + * + * @param sql SQL + */ public Optional> queryFirst(String sql) throws SQLException { return JdbcExecutor.queryFirst(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.HASH_MAP_MAPPER); } + /** + * 执行查询,将第一行数据转为 DbRecord + * + * @param sql SQL + */ public Optional queryFirstRecord(String sql) throws SQLException { return JdbcExecutor.queryFirst(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.RECORD_MAPPER); } + /** + * 查询第一行第一列,并转换为字符串 + * + * @param sql SQL + */ public Optional queryFirstString(String sql) throws SQLException { return JdbcExecutor.queryFirstString(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY); } + /** + * 查询第一行第一列,并转换为整数值 + * + * @param sql SQL + */ public OptionalInt queryFirstInt(String sql) throws SQLException { return JdbcExecutor.queryFirstInt(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY); } + /** + * 查询第一行第一列,并转换为长整型 + * + * @param sql SQL + */ public OptionalLong queryFirstLong(String sql) throws SQLException { return JdbcExecutor.queryFirstLong(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY); } + /** + * 查询第一行第一列,并转换为双精度浮点型 + * + * @param sql SQL + */ public OptionalDouble queryFirstDouble(String sql) throws SQLException { return JdbcExecutor.queryFirstDouble(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY); } + /** + * 查询第一行第一列,并转换为 {@link BigDecimal} + * + * @param sql SQL + */ public Optional queryFirstBigDecimal(String sql) throws SQLException { return JdbcExecutor.queryFirstBigDecimal(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY); @@ -547,24 +930,37 @@ public class SimpleJdbcTemplate { // #region - update & batchUpdate + /** + * 执行更新操作 + * + * @param sql 要执行的 SQL + * @param params 参数 + * @return 更新记录数 + */ public int update(String sql, Object[] params) throws SQLException { return JdbcExecutor.update(this.conn, sql, params); } + /** + * 执行更新操作 + * + * @param sql 要执行的 SQL + * @return 更新记录数 + */ public int update(String sql) throws SQLException { return JdbcExecutor.update(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY); } /** - * 执行 SQL 并更新后的数据 - * - * @param sql 要执行的 SQL 语句 + * 执行 SQL 并返回生成的 keys + * + * @param sql 要执行的 SQL * @param params 参数 - * @param rowMapper 结果映射规则 - * - * @return 更新的数据 + * @param rowMapper 行数据映射逻辑 + * + * @return generated keys * @throws SQLException 执行 SQL 遇到异常情况将抛出 */ public List update(String sql, Object[] params, RowMapper rowMapper) @@ -573,13 +969,12 @@ public class SimpleJdbcTemplate { } /** - * 执行 SQL 并更新后的数据 - * - * @param sql 要执行的 SQL 语句 - * @param params 参数 - * @param rowMapper 结果映射规则 - * - * @return 更新的数据 + * 执行 SQL 并返回生成的 keys + * + * @param sql 要执行的 SQL + * @param rowMapper 行数据映射逻辑 + * + * @return generated keys * @throws SQLException 执行 SQL 遇到异常情况将抛出 */ public List update(String sql, RowMapper rowMapper) @@ -587,11 +982,26 @@ public class SimpleJdbcTemplate { return JdbcExecutor.update(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper); } + /** + * 执行批量更新,批量更新数据,返回每条记录更新的行数 + * + * @param sql SQL 语句 + * @param params 参数列表 + * @param batchSize 每次批量更新的数据量 + */ public List batchUpdate(String sql, @Nullable Collection params, int batchSize) throws SQLException { return JdbcExecutor.batchUpdate(this.conn, sql, params, batchSize); } + /** + * 批量更新,返回更新成功的记录行数。发生异常时不中断操作,将异常存入 {@code exceptions} 中 + * + * @param sql sql语句 + * @param params 参数列表 + * @param batchSize 每次批量更新的数据量 + * @param exceptions 异常列表,用于记录异常信息 + */ public List batchUpdateAndIgnoreException(String sql, @Nullable Collection params, int batchSize, List exceptions) throws SQLException { @@ -602,6 +1012,14 @@ public class SimpleJdbcTemplate { // #region - internal + /** + * 执行查询,将查询结果按照指定逻辑进行处理并返回 + * + * @param conn 数据库连接 + * @param sql SQL + * @param params 参数 + * @param resultHandler 结果处理器,用于处理 {@link ResultSet} + */ private static T queryInternal(@Nonnull Connection conn, @Nonnull String sql, @Nullable Object[] params, @@ -615,6 +1033,14 @@ public class SimpleJdbcTemplate { } } + /** + * 执行查询,将查询结果的每一行数据按照指定逻辑进行处理,返回结果列表 + * + * @param conn 数据库连接 + * @param sql SQL + * @param params 参数 + * @param rowMapper {@link ResultSet} 中每一行的数据的处理逻辑 + */ private static List queryListInternal(@Nonnull Connection conn, @Nonnull String sql, @Nullable Object[] params, @@ -631,6 +1057,14 @@ public class SimpleJdbcTemplate { }); } + /** + * 执行查询,将查询结果的第一行数据按照指定逻辑进行处理,返回 {@link Optional} + * + * @param conn 数据库连接 + * @param sql SQL + * @param params 参数 + * @param rowMapper 行数据映射逻辑 + */ private static Optional queryFirstInternal(@Nonnull Connection conn, @Nonnull String sql, @Nullable Object[] params, @@ -648,6 +1082,14 @@ public class SimpleJdbcTemplate { // #region - query + /** + * 执行查询,并按照自定义处理逻辑对结果进行处理,将结果转换为指定类型并返回 + * + * @param conn 数据库连接 + * @param sql SQL + * @param params 参数 + * @param resultHandler 结果处理器,用于处理 {@link ResultSet} + */ private static T query(Connection conn, String sql, Object[] params, ResultHandler resultHandler) throws SQLException { assertConnectionNotNull(conn); @@ -660,6 +1102,14 @@ public class SimpleJdbcTemplate { // #region - queryList + /** + * 执行查询,将查询结果的每一行数据按照指定逻辑进行处理,返回结果列表 + * + * @param conn 数据库连接 + * @param sql SQL + * @param params 参数 + * @param rowMapper {@link ResultSet} 中每一行的数据的处理逻辑 + */ private static List queryList(Connection conn, String sql, Object[] params, RowMapper rowMapper) throws SQLException { assertConnectionNotNull(conn); @@ -668,6 +1118,14 @@ public class SimpleJdbcTemplate { return queryListInternal(conn, sql, params, rowMapper); } + /** + * 执行查询,返回结果映射为指定的类型。当结果为单列时使用 + * + * @param conn 数据库连接 + * @param sql SQL + * @param params 参数 + * @param clazz 将结果映射为指定的类型 + */ private static List queryList(Connection conn, String sql, Object[] params, Class clazz) throws SQLException { assertConnectionNotNull(conn); @@ -680,6 +1138,14 @@ public class SimpleJdbcTemplate { // #region - queryFirst + /** + * 执行查询,将查询结果的第一行数据按照指定逻辑进行处理,返回 {@link Optional} + * + * @param conn 数据库连接 + * @param sql SQL + * @param params 参数 + * @param rowMapper {@link ResultSet} 中每一行的数据的处理逻辑 + */ private static Optional queryFirst(Connection conn, String sql, Object[] params, RowMapper rowMapper) throws SQLException { assertConnectionNotNull(conn); @@ -688,6 +1154,14 @@ public class SimpleJdbcTemplate { return queryFirstInternal(conn, sql, params, rowMapper); } + /** + * 查询第一行第一列,并转换为指定类型 + * + * @param 目标类型 + * @param sql SQL + * @param params 参数 + * @param clazz 目标类型 + */ private static Optional queryFirst(Connection conn, String sql, Object[] params, Class clazz) throws SQLException { assertConnectionNotNull(conn); @@ -696,29 +1170,64 @@ public class SimpleJdbcTemplate { return queryFirstInternal(conn, sql, params, (rs, rowNumber) -> rs.getObject(1, clazz)); } + /** + * 查询第一行第一列,并转换为字符串 + * + * @param conn 数据库连接 + * @param sql SQL + * @param params 参数 + */ private static Optional queryFirstString(Connection conn, String sql, Object[] params) throws SQLException { return queryFirst(conn, sql, params, (rs, rowNumber) -> rs.getString(1)); } + /** + * 查询第一行第一列,并转换为整数值 + * + * @param conn 数据库连接 + * @param sql SQL + * @param params 参数 + */ private static OptionalInt queryFirstInt(Connection conn, String sql, Object[] params) throws SQLException { Optional result = queryFirst(conn, sql, params, (rs, rowNumber) -> rs.getInt(1)); return OptionalTools.toOptionalInt(result); } + /** + * 查询第一行第一列,并转换为长整型 + * + * @param conn 数据库连接 + * @param sql SQL + * @param params 参数 + */ private static OptionalLong queryFirstLong(Connection conn, String sql, Object[] params) throws SQLException { Optional result = queryFirst(conn, sql, params, (rs, rowNumber) -> rs.getLong(1)); return OptionalTools.toOptionalLong(result); } + /** + * 查询第一行第一列,并转换为双精度浮点型 + * + * @param conn 数据库连接 + * @param sql SQL + * @param params 参数 + */ private static OptionalDouble queryFirstDouble(Connection conn, String sql, Object[] params) throws SQLException { Optional result = queryFirst(conn, sql, params, (rs, rowNumber) -> rs.getDouble(1)); return OptionalTools.toOptionalDouble(result); } + /** + * 查询第一行第一列,并转换为 {@link BigDecimal} + * + * @param conn 数据库连接 + * @param sql SQL + * @param params 参数 + */ private static Optional queryFirstBigDecimal(Connection conn, String sql, Object[] params) throws SQLException { return queryFirst(conn, sql, params, (rs, rowNumber) -> rs.getBigDecimal(1)); @@ -728,6 +1237,14 @@ public class SimpleJdbcTemplate { // #region - update & batchUpdate + /** + * 执行更新操作 + * + * @param conn 数据库连接 + * @param sql 要执行的 SQL + * @param params 参数 + * @return 更新记录数 + */ private static int update(Connection conn, String sql, Object[] params) throws SQLException { assertConnectionNotNull(conn); @@ -739,13 +1256,14 @@ public class SimpleJdbcTemplate { } /** - * 执行 SQL 并更新后的数据 - * - * @param sql 要执行的 SQL 语句 + * 执行 SQL 并返回生成的 keys + * + * @param conn 数据库连接 + * @param sql 要执行的 SQL * @param params 参数 - * @param rowMapper 结果映射规则 - * - * @return 更新的数据 + * @param rowMapper 行数据映射逻辑 + * + * @return generated keys * @throws SQLException 执行 SQL 遇到异常情况将抛出 */ private static List update(Connection conn, String sql, Object[] params, RowMapper rowMapper) @@ -768,6 +1286,14 @@ public class SimpleJdbcTemplate { } } + /** + * 执行批量更新,批量更新数据,返回每条记录更新的行数 + * + * @param conn 数据库连接 + * @param sql SQL 语句 + * @param params 参数列表 + * @param batchSize 每次批量更新的数据量 + */ private static List batchUpdate(Connection conn, String sql, Collection params, int batchSize) throws SQLException { assertConnectionNotNull(conn); @@ -796,6 +1322,15 @@ public class SimpleJdbcTemplate { } } + /** + * 批量更新,返回更新成功的记录行数。发生异常时不中断操作,将异常存入 {@code exceptions} 中 + * + * @param conn 数据库连接 + * @param sql sql语句 + * @param params 参数列表 + * @param batchSize 每次批量更新的数据量 + * @param exceptions 异常列表,用于记录异常信息 + */ private static List batchUpdateAndIgnoreException(Connection conn, String sql, @Nullable Collection params, int batchSize, List exceptions) @@ -837,6 +1372,9 @@ public class SimpleJdbcTemplate { } } + /** + * 填充参数 + */ private static void fillStatement(@Nonnull PreparedStatement stmt, @Nullable Object[] params) throws SQLException { if (params != null && params.length > 0) { @@ -859,7 +1397,7 @@ public class SimpleJdbcTemplate { } } - // #region - Asserts + // #region - 参数校验 private static void assertConnectionNotNull(Connection conn) { AssertTools.checkArgumentNotNull(conn, "The argument \"conn\" could not be null.");