diff --git a/CHANGELOG.md b/CHANGELOG.md index 283e771..9af9ce0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,25 @@ - **`DefaultBeanRowMapper.of()` 不再抛出 `SQLException`**:工厂方法在反射异常时改为抛出非受检异常 `IllegalStateException`。调用方如果 `catch (SQLException e)` 包裹 `of()` 调用,该捕获将失效,需移除相关 `catch` 块或改为捕获 `IllegalStateException`。 +### 新增 + +- `queryValueOrDefault(sql, params, Class, T defaultValue)`:查询单行单列,结果为空时返回指定默认值 +- `queryValueOrDefault(sql, Class, T defaultValue)`:无参数重载 +- 补充 `QueryTest` 中 `queryValueOrDefault` 单元测试 6 个 + +### 重构 + +**将单列查询方法标记为过时,消除 Class 参数重载歧义** + +- `queryList(sql, params, Class)` → 已过时,请使用 `queryValues(sql, params, Class)` + 语义明确为"多行单列 → 值列表",不与整行 `RowMapper` 重载混淆 +- `queryFirst(sql, params, Class)` → 已过时,请使用 `queryValue(sql, params, Class)` + 语义明确为"单行单列 → 单值",不与整行 `RowMapper` 重载混淆 +- 同时将对应的无参数重载标记为过时: + - `queryList(sql, Class)` → 请使用 `queryValues(sql, Class)` + - `queryFirst(sql, Class)` → 请使用 `queryValue(sql, Class)` +- 旧方法将在后续版本中移除 + ### 文档 - 优化 `DefaultBeanRowMapper` 类注释,明确性能限制和使用建议 diff --git a/README.md b/README.md index eff9ce1..7cefc81 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ List accounts = jdbcTemplate.query( ); // 查询列表(单列) -List usernames = jdbcTemplate.queryList( +List usernames = jdbcTemplate.queryValues( "SELECT username FROM account WHERE deleted = 0 AND username LIKE ? AND org_no = ?", buildParams("admin%", "0000"), String.class @@ -117,11 +117,18 @@ Optional account = jdbcTemplate.queryFirst( ); // 查询单个值(所有 ResultSet.getObject 支持的类型) -Long count = jdbcTemplate.queryFirst( +Long count = jdbcTemplate.queryValue( "SELECT COUNT(*) FROM account WHERE deleted = 0 AND username LIKE ? AND org_no = ?", buildParams("admin%", "0000"), Long.class ).orElse(0L); +// 或者 +Long count = jdbcTemplate.queryValueOrDefault( + "SELECT COUNT(*) FROM account WHERE deleted = 0 AND username LIKE ? AND org_no = ?", + buildParams("admin%", "0000"), + Long.class, + 0L +); // 查询 Boolean 值 boolean exists = jdbcTemplate.queryBoolean( @@ -245,14 +252,15 @@ jdbcTemplate.transaction().commitIfTrue(jdbc -> { | :--- | :--- | | `query(sql, params, resultHandler)` | 最基础的查询,通过 `ResultHandler` 自定义完整的映射逻辑。 | | `queryList(sql, params, rowMapper)` | 查询列表,通过 `RowMapper` 逐行映射。 | -| `queryList(sql, params, Class)` | 单列查询列表,每行提取第一列并转换为指定类型。 | | `queryList(sql, params)` | 查询列表,每行自动转换为 `Map`。 | | `queryFirst(sql, params, rowMapper)` | 查询第一行,通过 `RowMapper` 映射,返回 `Optional`。 | -| `queryFirst(sql, params, Class)` | 查询第一行第一列,返回 `Optional`。 | | `queryFirst(sql, params)` | 查询第一行,返回 `Optional>`。 | +| `queryValues(sql, params, Class)` | 单列查询列表,每行提取第一列并转换为指定类型。 | +| `queryValue(sql, params, Class)` | 查询第一行第一列,返回 `Optional`。 | +| `queryValueOrDefault(sql, params, Class, default)` | 查询第一行第一列,结果为空时返回默认值。适用于 COUNT/SUM 等聚合查询。 | | `queryBoolean(sql, params)` | 查询第一行第一列并转换为 `boolean`,若结果为空则返回 `false`。 | -*💡 提示:以上方法均有省略 `params` 的重载(如 `queryList(sql, rowMapper)`),适用于不含占位符的 SQL 语句。* +*💡 提示:以上方法均有省略 `params` 的重载(如 `queryList(sql, rowMapper)`),适用于不含占位符的 SQL 语句。`queryValues`、`queryValue`、`queryValueOrDefault` 同理。* ### 4.2 结果映射策略 diff --git a/src/main/java/xyz/zhouxy/jdbc/JdbcOperationSupport.java b/src/main/java/xyz/zhouxy/jdbc/JdbcOperationSupport.java index a63d2f8..91367e5 100644 --- a/src/main/java/xyz/zhouxy/jdbc/JdbcOperationSupport.java +++ b/src/main/java/xyz/zhouxy/jdbc/JdbcOperationSupport.java @@ -93,14 +93,14 @@ class JdbcOperationSupport { } /** - * 执行查询,返回结果映射为指定的类型。当结果为单列时使用 + * 执行查询,只取结果集每行第一列的值,映射为指定类型并返回列表 * * @param conn 数据库连接 * @param sql SQL * @param params 参数 * @param clazz 将结果映射为指定的类型 */ - static List queryList(Connection conn, String sql, Object[] params, Class clazz) + static List queryValues(Connection conn, String sql, Object[] params, Class clazz) throws SQLException { assertConnectionNotNull(conn); assertSqlNotNull(sql); @@ -129,14 +129,15 @@ class JdbcOperationSupport { } /** - * 查询第一行第一列,并转换为指定类型 + * 执行查询,只取结果集第一行第一列的值,映射为指定类型并返回 * + * @param conn 数据库连接 * @param 目标类型 * @param sql SQL * @param params 参数 * @param clazz 目标类型 */ - static T queryFirst(Connection conn, String sql, Object[] params, Class clazz) + static T queryValue(Connection conn, String sql, Object[] params, Class clazz) throws SQLException { assertConnectionNotNull(conn); assertSqlNotNull(sql); diff --git a/src/main/java/xyz/zhouxy/jdbc/JdbcOperations.java b/src/main/java/xyz/zhouxy/jdbc/JdbcOperations.java index 3aadfe3..2d74608 100644 --- a/src/main/java/xyz/zhouxy/jdbc/JdbcOperations.java +++ b/src/main/java/xyz/zhouxy/jdbc/JdbcOperations.java @@ -87,17 +87,18 @@ public interface JdbcOperations { throws SQLException; /** - * 执行查询,返回结果映射为指定的类型。当结果为单列时使用 + * 执行查询,只取结果集每行第一列的值,映射为指定类型并返回列表。 + * 适用于 {@code SELECT single_column FROM ...} 单列查询场景。 * - * @param 目标类型 + * @param 目标类型(对应结果集第一列的 Java 类型) * @param sql SQL * @param params 参数 * @param clazz 目标类型 * - * @return 映射结果。如果查询结果为空,则返回空列表 + * @return 每一行第一列的值列表。如果查询结果为空,则返回空列表 * @throws SQLException SQL异常 */ - List queryList(String sql, Object[] params, Class clazz) + List queryValues(String sql, Object[] params, Class clazz) throws SQLException; /** @@ -128,18 +129,39 @@ public interface JdbcOperations { } /** - * 执行查询,返回结果映射为指定的类型。当结果为单列时使用 + * 执行查询,只取结果集每行第一列的值,映射为指定类型并返回列表。 + * 适用于 {@code SELECT single_column FROM ...} 单列查询场景。 * * @param 目标类型 * @param sql SQL * @param clazz 将结果映射为指定的类型 * - * @return 查询结果 + * @return 每一行第一列的值列表。如果查询结果为空,则返回空列表 * @throws SQLException SQL 异常 */ + default List queryValues(String sql, Class clazz) + throws SQLException { + return queryValues(sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz); + } + + /** + * @deprecated 自 1.1.0 起,请使用 {@link #queryValues(String, Object[], Class)}。 + * 此方法将在后续版本中移除。 + */ + @Deprecated + default List queryList(String sql, Object[] params, Class clazz) + throws SQLException { + return queryValues(sql, params, clazz); + } + + /** + * @deprecated 自 1.1.0 起,请使用 {@link #queryValues(String, Class)}。 + * 此方法将在后续版本中移除。 + */ + @Deprecated default List queryList(String sql, Class clazz) throws SQLException { - return queryList(sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz); + return queryValues(sql, clazz); } /** @@ -174,17 +196,18 @@ public interface JdbcOperations { throws SQLException; /** - * 查询第一行第一列,并转换为指定类型 + * 执行查询,只取结果集第一行第一列的值,映射为指定类型并返回。 + * 适用于 {@code SELECT single_column FROM ... WHERE ...} 单列单行查询场景。 * * @param 目标类型 * @param sql SQL * @param params 参数 * @param clazz 目标类型 * - * @return 查询结果 + * @return 第一行第一列的值。如果查询结果为空,则返回 {@code Optional.empty()} * @throws SQLException SQL 异常 */ - Optional queryFirst(String sql, Object[] params, Class clazz) + Optional queryValue(String sql, Object[] params, Class clazz) throws SQLException; /** @@ -215,18 +238,39 @@ public interface JdbcOperations { } /** - * 查询第一行第一列,并转换为指定类型 + * 执行查询,只取结果集第一行第一列的值,映射为指定类型并返回。 + * 适用于 {@code SELECT single_column FROM ... WHERE ...} 单列单行查询场景。 * * @param 目标类型 * @param sql SQL * @param clazz 目标类型 * - * @return 第一行第一列的值,如果查询结果为空,则返回 {@code Optional#empty()} + * @return 第一行第一列的值,如果查询结果为空,则返回 {@code Optional.empty()} * @throws SQLException SQL 异常 */ + default Optional queryValue(String sql, Class clazz) + throws SQLException { + return queryValue(sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz); + } + + /** + * @deprecated 自 1.1.0 起,请使用 {@link #queryValue(String, Object[], Class)}。 + * 此方法将在后续版本中移除。 + */ + @Deprecated + default Optional queryFirst(String sql, Object[] params, Class clazz) + throws SQLException { + return queryValue(sql, params, clazz); + } + + /** + * @deprecated 自 1.1.0 起,请使用 {@link #queryValue(String, Class)}。 + * 此方法将在后续版本中移除。 + */ + @Deprecated default Optional queryFirst(String sql, Class clazz) throws SQLException { - return queryFirst(sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz); + return queryValue(sql, clazz); } /** @@ -242,6 +286,43 @@ public interface JdbcOperations { return queryFirst(sql, ParamBuilder.EMPTY_OBJECT_ARRAY); } + /** + * 执行查询,只取结果集第一行第一列的值,映射为指定类型并返回。 + * 如果查询结果为空,则返回指定的默认值。 + * 适用于 {@code SELECT COUNT(*)}、{@code SELECT MAX(...)} 等聚合查询场景。 + * + * @param 目标类型 + * @param sql SQL + * @param params 参数 + * @param clazz 目标类型 + * @param defaultValue 查询结果为空时返回的默认值 + * + * @return 第一行第一列的值,如果查询结果为空则返回 {@code defaultValue} + * @throws SQLException SQL 异常 + */ + default T queryValueOrDefault(String sql, Object[] params, Class clazz, T defaultValue) + throws SQLException { + return queryValue(sql, params, clazz).orElse(defaultValue); + } + + /** + * 执行查询,只取结果集第一行第一列的值,映射为指定类型并返回。 + * 如果查询结果为空,则返回指定的默认值。 + * 适用于 {@code SELECT COUNT(*)}、{@code SELECT MAX(...)} 等聚合查询场景。 + * + * @param 目标类型 + * @param sql SQL + * @param clazz 目标类型 + * @param defaultValue 查询结果为空时返回的默认值 + * + * @return 第一行第一列的值,如果查询结果为空则返回 {@code defaultValue} + * @throws SQLException SQL 异常 + */ + default T queryValueOrDefault(String sql, Class clazz, T defaultValue) + throws SQLException { + return queryValueOrDefault(sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz, defaultValue); + } + /** * 查询第一行第一列并转换为 boolean * diff --git a/src/main/java/xyz/zhouxy/jdbc/SimpleJdbcTemplate.java b/src/main/java/xyz/zhouxy/jdbc/SimpleJdbcTemplate.java index 6a02976..106991c 100644 --- a/src/main/java/xyz/zhouxy/jdbc/SimpleJdbcTemplate.java +++ b/src/main/java/xyz/zhouxy/jdbc/SimpleJdbcTemplate.java @@ -96,10 +96,10 @@ public class SimpleJdbcTemplate implements JdbcOperations { /** {@inheritDoc} */ @Override - public List queryList(String sql, Object[] params, Class clazz) + public List queryValues(String sql, Object[] params, Class clazz) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { - return JdbcOperationSupport.queryList(conn, sql, params, clazz); + return JdbcOperationSupport.queryValues(conn, sql, params, clazz); } } @@ -128,10 +128,10 @@ public class SimpleJdbcTemplate implements JdbcOperations { /** {@inheritDoc} */ @Override - public Optional queryFirst(String sql, Object[] params, Class clazz) + public Optional queryValue(String sql, Object[] params, Class clazz) throws SQLException { try (Connection conn = this.dataSource.getConnection()) { - final T result = JdbcOperationSupport.queryFirst(conn, sql, params, clazz); + final T result = JdbcOperationSupport.queryValue(conn, sql, params, clazz); return Optional.ofNullable(result); } } @@ -153,7 +153,7 @@ public class SimpleJdbcTemplate implements JdbcOperations { throws SQLException { try (Connection conn = this.dataSource.getConnection()) { final Boolean result = JdbcOperationSupport - .queryFirst(conn, sql, params, Boolean.class); + .queryValue(conn, sql, params, Boolean.class); return Boolean.TRUE.equals(result); } } diff --git a/src/main/java/xyz/zhouxy/jdbc/TransactionTemplate.java b/src/main/java/xyz/zhouxy/jdbc/TransactionTemplate.java index f5a1c87..5149979 100644 --- a/src/main/java/xyz/zhouxy/jdbc/TransactionTemplate.java +++ b/src/main/java/xyz/zhouxy/jdbc/TransactionTemplate.java @@ -181,9 +181,9 @@ public class TransactionTemplate { /** {@inheritDoc} */ @Override - public List queryList(String sql, Object[] params, Class clazz) + public List queryValues(String sql, Object[] params, Class clazz) throws SQLException { - return JdbcOperationSupport.queryList(this.conn, sql, params, clazz); + return JdbcOperationSupport.queryValues(this.conn, sql, params, clazz); } /** {@inheritDoc} */ @@ -207,9 +207,9 @@ public class TransactionTemplate { /** {@inheritDoc} */ @Override - public Optional queryFirst(String sql, Object[] params, Class clazz) + public Optional queryValue(String sql, Object[] params, Class clazz) throws SQLException { - final T result = JdbcOperationSupport.queryFirst(this.conn, sql, params, clazz); + final T result = JdbcOperationSupport.queryValue(this.conn, sql, params, clazz); return Optional.ofNullable(result); } @@ -227,7 +227,7 @@ public class TransactionTemplate { public boolean queryBoolean(String sql, Object[] params) throws SQLException { final Boolean result = JdbcOperationSupport - .queryFirst(this.conn, sql, params, Boolean.class); + .queryValue(this.conn, sql, params, Boolean.class); return Boolean.TRUE.equals(result); } diff --git a/src/test/java/xyz/zhouxy/jdbc/test/BatchUpdateTest.java b/src/test/java/xyz/zhouxy/jdbc/test/BatchUpdateTest.java index a5b8590..bfd557b 100644 --- a/src/test/java/xyz/zhouxy/jdbc/test/BatchUpdateTest.java +++ b/src/test/java/xyz/zhouxy/jdbc/test/BatchUpdateTest.java @@ -199,7 +199,7 @@ class BatchUpdateTest extends BaseH2Test { void testBatchUpdateQuietlyFalseInterrupted() throws SQLException { SimpleJdbcTemplate template = createTemplate(); - int count0 = template.queryFirst("SELECT COUNT(*) FROM users", Integer.class) + int count0 = template.queryValue("SELECT COUNT(*) FROM users", Integer.class) .orElse(0); List params = buildBatchParams(userListContainingInvalidData, a -> new Object[] { a.getUsername(), a.getEmail(), a.getAge(), a.getBalance(), a.getActive() }); @@ -231,7 +231,7 @@ class BatchUpdateTest extends BaseH2Test { assertNull(result.getUpdateCounts(3)); assertNull(result.getUpdateCounts(4)); - Optional count8 = template.queryFirst("SELECT COUNT(*) FROM users", Integer.class); + Optional count8 = template.queryValue("SELECT COUNT(*) FROM users", Integer.class); assertEquals(count0 + 8, count8.get().intValue()); } @@ -242,7 +242,7 @@ class BatchUpdateTest extends BaseH2Test { void testBatchUpdateQuietlyTrue() throws SQLException { SimpleJdbcTemplate template = createTemplate(); - int count0 = template.queryFirst("SELECT COUNT(*) FROM users", Integer.class) + int count0 = template.queryValue("SELECT COUNT(*) FROM users", Integer.class) .orElse(0); List params = buildBatchParams(userListContainingInvalidData, a -> new Object[] { a.getUsername(), a.getEmail(), a.getAge(), a.getBalance(), a.getActive() }); @@ -261,7 +261,7 @@ class BatchUpdateTest extends BaseH2Test { assertArrayEquals(new int[] { Statement.EXECUTE_FAILED, 1, 1 }, result.getUpdateCounts(3)); assertArrayEquals(new int[] { 1 }, result.getUpdateCounts(4)); - Optional count11 = template.queryFirst("SELECT COUNT(*) FROM users", Integer.class); + Optional count11 = template.queryValue("SELECT COUNT(*) FROM users", Integer.class); assertEquals(count0 + 11, count11.get().intValue()); } diff --git a/src/test/java/xyz/zhouxy/jdbc/test/QueryTest.java b/src/test/java/xyz/zhouxy/jdbc/test/QueryTest.java index aaa0080..aef23d3 100644 --- a/src/test/java/xyz/zhouxy/jdbc/test/QueryTest.java +++ b/src/test/java/xyz/zhouxy/jdbc/test/QueryTest.java @@ -18,7 +18,7 @@ import xyz.zhouxy.jdbc.ResultHandler; import xyz.zhouxy.jdbc.SimpleJdbcTemplate; /** - * 查询 API 测试:query、queryList、queryFirst、queryBoolean。 + * 查询 API 测试:query、queryList、queryFirst、queryValues、queryValue、queryBoolean。 */ @DisplayName("SimpleJdbcTemplate 查询操作") class QueryTest extends BaseH2Test { @@ -119,28 +119,28 @@ class QueryTest extends BaseH2Test { assertEquals(5, users.size()); } - // ==================== queryList(Class) ==================== + // ==================== queryValues(Class) ==================== @Test - @DisplayName("queryList(Class):单列查询返回 String 列表") - void testQueryListWithClassString() throws SQLException { + @DisplayName("queryValues(Class):单列查询返回 String 列表") + void testQueryValuesWithClassString() throws SQLException { SimpleJdbcTemplate template = createTemplate(); - List usernames = template.queryList( + List usernames = template.queryValues( "SELECT username FROM users ORDER BY id", String.class); - logger.info("queryList(Class) 返回用户名: {}", usernames); + logger.info("queryValues(Class) 返回用户名: {}", usernames); assertEquals(5, usernames.size()); assertTrue(usernames.contains("alice")); } @Test - @DisplayName("queryList(Class):空结果集返回空列表") - void testQueryListEmptyResult() throws SQLException { + @DisplayName("queryValues(Class):空结果集返回空列表") + void testQueryValuesEmptyResult() throws SQLException { SimpleJdbcTemplate template = createTemplate(); - List result = template.queryList( + List result = template.queryValues( "SELECT username FROM users WHERE id = ?", buildParams(999), String.class); @@ -215,14 +215,14 @@ class QueryTest extends BaseH2Test { assertTrue(user.isPresent()); } - // ==================== queryFirst(Class) ==================== + // ==================== queryValue(Class) ==================== @Test - @DisplayName("queryFirst(Class):查询第一行第一列") - void testQueryFirstWithClass() throws SQLException { + @DisplayName("queryValue(Class):查询第一行第一列") + void testQueryValueWithClass() throws SQLException { SimpleJdbcTemplate template = createTemplate(); - Optional username = template.queryFirst( + Optional username = template.queryValue( "SELECT username FROM users ORDER BY id", String.class); @@ -231,11 +231,11 @@ class QueryTest extends BaseH2Test { } @Test - @DisplayName("queryFirst(Class):空结果返回 Optional.empty()") - void testQueryFirstClassEmpty() throws SQLException { + @DisplayName("queryValue(Class):空结果返回 Optional.empty()") + void testQueryValueClassEmpty() throws SQLException { SimpleJdbcTemplate template = createTemplate(); - Optional result = template.queryFirst( + Optional result = template.queryValue( "SELECT username FROM users WHERE id = ?", buildParams(999), String.class); @@ -244,11 +244,11 @@ class QueryTest extends BaseH2Test { @Test - @DisplayName("queryFirst + Class:统计总行数") - void testQueryFirstWithClass_queryCount() throws SQLException { + @DisplayName("queryValue + Class:统计总行数") + void testQueryValueWithClass_queryCount() throws SQLException { SimpleJdbcTemplate template = createTemplate(); - int count = template.queryFirst( + int count = template.queryValue( "SELECT COUNT(*) FROM users", new Object[0], Integer.class) @@ -259,11 +259,11 @@ class QueryTest extends BaseH2Test { } @Test - @DisplayName("queryFirst + Class:聚合求和") - void testQueryFirstWithClass_queryAggregation() throws SQLException { + @DisplayName("queryValue + Class:聚合求和") + void testQueryValueWithClass_queryAggregation() throws SQLException { SimpleJdbcTemplate template = createTemplate(); - Long totalBalance = template.queryFirst( + Long totalBalance = template.queryValue( "SELECT SUM(balance) FROM users", new Object[0], Long.class) @@ -273,6 +273,81 @@ class QueryTest extends BaseH2Test { assertNotNull(totalBalance); } + // ==================== queryValueOrDefault ==================== + + @Test + @DisplayName("queryValueOrDefault:有结果时返回值") + void testQueryValueOrDefaultWithResult() throws SQLException { + SimpleJdbcTemplate template = createTemplate(); + + String username = template.queryValueOrDefault( + "SELECT username FROM users WHERE id = ?", + new Object[]{1}, String.class, "default"); + + assertEquals("alice", username); + } + + @Test + @DisplayName("queryValueOrDefault:无结果时返回默认值") + void testQueryValueOrDefaultWithDefault() throws SQLException { + SimpleJdbcTemplate template = createTemplate(); + + String username = template.queryValueOrDefault( + "SELECT username FROM users WHERE id = ?", + new Object[]{999}, String.class, "unknown"); + + assertEquals("unknown", username); + } + + @Test + @DisplayName("queryValueOrDefault:COUNT 聚合查询") + void testQueryValueOrDefaultCount() throws SQLException { + SimpleJdbcTemplate template = createTemplate(); + + long count = template.queryValueOrDefault( + "SELECT COUNT(*) FROM users", + new Object[0], Long.class, 0L); + + assertEquals(5L, count); + } + + @Test + @DisplayName("queryValueOrDefault:SUM 聚合查询") + void testQueryValueOrDefaultSum() throws SQLException { + SimpleJdbcTemplate template = createTemplate(); + + long totalBalance = template.queryValueOrDefault( + "SELECT SUM(balance) FROM users", + new Object[0], Long.class, 0L); + + assertTrue(totalBalance > 0); + logger.info("queryValueOrDefault SUM 结果: {}", totalBalance); + } + + @Test + @DisplayName("queryValueOrDefault:无参数重载") + void testQueryValueOrDefaultNoParams() throws SQLException { + SimpleJdbcTemplate template = createTemplate(); + + long count = template.queryValueOrDefault( + "SELECT COUNT(*) FROM users", + Long.class, 0L); + + assertEquals(5L, count); + } + + @Test + @DisplayName("queryValueOrDefault:空表 COUNT 返回默认值 0") + void testQueryValueOrDefaultEmptyTable() throws SQLException { + SimpleJdbcTemplate template = createTemplate(); + + long count = template.queryValueOrDefault( + "SELECT COUNT(*) FROM users WHERE id = ?", + new Object[]{999}, Long.class, 0L); + + assertEquals(0L, count); + } + // ==================== queryFirst(Map) ==================== @Test @@ -385,7 +460,7 @@ class QueryTest extends BaseH2Test { SimpleJdbcTemplate template = createTemplate(); assertThrows(SQLException.class, () -> - template.queryList("SELECT * FROM non_existent_table", + template.queryValues("SELECT * FROM non_existent_table", new Object[0], String.class)); } @@ -395,7 +470,7 @@ class QueryTest extends BaseH2Test { SimpleJdbcTemplate template = createTemplate(); assertThrows(SQLException.class, () -> - template.queryList("SELEC * FROM users", + template.queryValues("SELEC * FROM users", new Object[0], String.class)); } diff --git a/src/test/java/xyz/zhouxy/jdbc/test/TransactionTest.java b/src/test/java/xyz/zhouxy/jdbc/test/TransactionTest.java index ffd7679..89bcadd 100644 --- a/src/test/java/xyz/zhouxy/jdbc/test/TransactionTest.java +++ b/src/test/java/xyz/zhouxy/jdbc/test/TransactionTest.java @@ -44,12 +44,12 @@ class TransactionTest extends BaseH2Test { }); // 验证事务已提交 - Optional newUser = template.queryFirst( + Optional newUser = template.queryValue( "SELECT username FROM users WHERE username = ?", buildParams("txUser1"), String.class); assertTrue(newUser.isPresent()); - Optional balance = template.queryFirst( + Optional balance = template.queryValue( "SELECT balance FROM users WHERE username = ?", buildParams("alice"), Long.class); assertEquals(Long.valueOf(99999L), balance.orElse(null)); @@ -65,7 +65,7 @@ class TransactionTest extends BaseH2Test { SimpleJdbcTemplate template = createTemplate(); // 记录原始 balance - Optional originalBalance = template.queryFirst( + Optional originalBalance = template.queryValue( "SELECT balance FROM users WHERE username = ?", buildParams("alice"), Long.class); @@ -85,13 +85,13 @@ class TransactionTest extends BaseH2Test { assertEquals("模拟业务异常", ex.getCause().getMessage()); // 验证更新已回滚 - Optional currentBalance = template.queryFirst( + Optional currentBalance = template.queryValue( "SELECT balance FROM users WHERE username = ?", buildParams("alice"), Long.class); assertEquals(originalBalance.orElse(null), currentBalance.orElse(null)); // 验证插入已回滚 - Optional rolledBackUser = template.queryFirst( + Optional rolledBackUser = template.queryValue( "SELECT username FROM users WHERE username = ?", buildParams("txUser2"), String.class); assertFalse(rolledBackUser.isPresent()); @@ -114,7 +114,7 @@ class TransactionTest extends BaseH2Test { // 验证插入已回滚 assertDoesNotThrow(() -> { - Optional user = template.queryFirst( + Optional user = template.queryValue( "SELECT username FROM users WHERE username = ?", buildParams("validUser"), String.class); assertFalse(user.isPresent()); @@ -135,7 +135,7 @@ class TransactionTest extends BaseH2Test { }); // 验证数据已持久化 - Optional user = template.queryFirst( + Optional user = template.queryValue( "SELECT username FROM users WHERE username = ?", buildParams("cftUser"), String.class); assertTrue(user.isPresent()); @@ -155,7 +155,7 @@ class TransactionTest extends BaseH2Test { }); // 验证数据已回滚 - Optional user = template.queryFirst( + Optional user = template.queryValue( "SELECT username FROM users WHERE username = ?", buildParams("cffUser"), String.class); assertFalse(user.isPresent()); @@ -177,7 +177,7 @@ class TransactionTest extends BaseH2Test { // 验证回滚 assertDoesNotThrow(() -> { - Optional user = template.queryFirst( + Optional user = template.queryValue( "SELECT username FROM users WHERE username = ?", buildParams("exUser"), String.class); assertFalse(user.isPresent()); @@ -196,7 +196,7 @@ class TransactionTest extends BaseH2Test { buildParams("visible", "visible@test.com")); // 在同一事务内可以查询到刚插入的数据 - Optional user = ops.queryFirst( + Optional user = ops.queryValue( "SELECT username FROM users WHERE username = ?", buildParams("visible"), String.class); assertTrue(user.isPresent());