refactor: 优化JDBC操作实现并改进事务异常处理

- 修改BatchUpdateResult类方法访问权限为包私有
- 在DefaultBeanRowMapper中使用getColumnLabel替代getColumnName
- 为JdbcOperations接口添加默认实现方法,简化API调用
- 添加TransactionException类用于包装事务执行过程中的异常
This commit is contained in:
2026-05-23 03:12:33 +08:00
parent 51c1f4d016
commit 05b59e69f0
9 changed files with 164 additions and 253 deletions

View File

@@ -33,7 +33,7 @@ public class BatchUpdateResult {
private int completeBatchCount;
public BatchUpdateResult(int total, int batchCount, int batchSize) {
BatchUpdateResult(int total, int batchCount, int batchSize) {
this.total = total;
this.batchCount = batchCount;
this.batchSize = batchSize;
@@ -45,7 +45,7 @@ public class BatchUpdateResult {
/**
* 记录成功批次
*/
public void recordSuccessBatch(int batchIndex, int[] updateCounts) {
void recordSuccessBatch(int batchIndex, int[] updateCounts) {
this.completeBatchCount++;
this.allUpdateCounts.put(batchIndex, updateCounts);
this.successBatchCount++;
@@ -54,7 +54,7 @@ public class BatchUpdateResult {
/**
* 记录失败批次
*/
public void recordErrorBatch(int batchIndex, int[] updateCounts, Throwable cause) {
void recordErrorBatch(int batchIndex, int[] updateCounts, Throwable cause) {
this.completeBatchCount++;
this.allUpdateCounts.put(batchIndex, updateCounts);
this.allErrorsInfo.put(batchIndex, new BatchUpdateErrorInfo(batchIndex, cause));
@@ -66,7 +66,7 @@ public class BatchUpdateResult {
/**
* 中断
*/
public void interrupt() {
void interrupt() {
this.status = BatchUpdateStatus.INTERRUPTED;
}

View File

@@ -50,6 +50,7 @@ import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
* <li>使用反射获取类型信息,也是使用反射调用无参构造器和 {@code setter} 方法。</li>
* <li>{@code propertyColMap} 未指定的列名和属性名的映射时,默认 JavaBean 的属性名为小驼峰,列名为小写蛇形命名。</li>
* <li>从{@link ResultSet} 中获取属性值时,使用 {@link ResultSet#getObject(String, Class)} 获取。</li>
* <li>JavaBean 属性仅支持引用类型,不支持基本数据类型。</li>
* <li>实际使用中还是建议针对目标类型自定义 {@link RowMapper}。</li>
* </ul>
* </p>
@@ -119,7 +120,7 @@ public class DefaultBeanRowMapper<T> implements RowMapper<T> {
ResultSetMetaData metaData = rs.getMetaData();
// 遍历结果的每一列
for (int i = 1; i <= metaData.getColumnCount(); i++) {
String colName = metaData.getColumnName(i);
String colName = metaData.getColumnLabel(i);
// 获取查询结果列名对应的属性,调用 setter
PropertyDescriptor propertyDescriptor = this.colPropertyMap.get(colName);
if (propertyDescriptor != null) {

View File

@@ -25,8 +25,10 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import java.sql.Types;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -140,6 +142,9 @@ class JdbcOperationSupport {
/**
* 查询第一行第一列并转换为 boolean
*
* <p>
* <b>注:如果查询结果为空,则返回 {@code false}。</b>
*
* @param conn 数据库连接
* @param sql SQL
* @param params 参数
@@ -187,7 +192,7 @@ class JdbcOperationSupport {
assertConnectionNotNull(conn);
assertSqlNotNull(sql);
assertRowMapperNotNull(rowMapper);
final List<T> result = new LinkedList<>();
final List<T> result = Lists.newArrayList();
try (PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
fillStatement(stmt, params);
stmt.executeUpdate();
@@ -209,7 +214,6 @@ class JdbcOperationSupport {
* @param sql sql语句
* @param params 参数列表
* @param batchSize 每次批量更新的数据量
* @param exceptions 空列表,用于记录异常信息
* @param quietly 静默分批更新。
* 如果 {@code quietly} 为 {@code true},分批更新过程中发生异常不中断操作;
* 如果 {@code quietly} 为 {@code false},分批更新过程中发生异常即中断操作,并返回结果。
@@ -313,7 +317,7 @@ class JdbcOperationSupport {
@Nonnull RowMapper<T> rowMapper)
throws SQLException {
return queryInternal(conn, sql, params, rs -> {
List<T> result = new LinkedList<>();
List<T> result = Lists.newArrayList();
int rowNumber = 0;
while (rs.next()) {
T e = rowMapper.mapRow(rs, rowNumber++);
@@ -352,7 +356,10 @@ class JdbcOperationSupport {
Object param;
for (int i = 0; i < params.length; i++) {
param = params[i];
if (param instanceof java.sql.Date) {
if (param == null) {
stmt.setObject(i + 1, null, Types.OTHER);
}
else if (param instanceof java.sql.Date) {
stmt.setDate(i + 1, (java.sql.Date) param);
}
else if (param instanceof java.sql.Time) {

View File

@@ -55,8 +55,10 @@ public interface JdbcOperations {
* @param sql SQL
* @param resultHandler 结果处理器,用于处理 {@link ResultSet}
*/
<T> T query(String sql, ResultHandler<T> resultHandler)
throws SQLException;
default <T> T query(String sql, ResultHandler<T> resultHandler)
throws SQLException {
return query(sql, ParamBuilder.EMPTY_OBJECT_ARRAY, resultHandler);
}
// #endregion
@@ -97,8 +99,10 @@ public interface JdbcOperations {
* @param sql SQL
* @param rowMapper {@link ResultSet} 中每一行的数据的处理逻辑
*/
<T> List<T> queryList(String sql, RowMapper<T> rowMapper)
throws SQLException;
default <T> List<T> queryList(String sql, RowMapper<T> rowMapper)
throws SQLException {
return queryList(sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
/**
* 执行查询,返回结果映射为指定的类型。当结果为单列时使用
@@ -106,16 +110,20 @@ public interface JdbcOperations {
* @param sql SQL
* @param clazz 将结果映射为指定的类型
*/
<T> List<T> queryList(String sql, Class<T> clazz)
throws SQLException;
default <T> List<T> queryList(String sql, Class<T> clazz)
throws SQLException {
return queryList(sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz);
}
/**
* 执行查询,每一行数据映射为 {@code Map<String, Object>},返回结果列表
*
* @param sql SQL
*/
List<Map<String, Object>> queryList(String sql)
throws SQLException;
default List<Map<String, Object>> queryList(String sql)
throws SQLException {
return queryList(sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
// #endregion
@@ -157,8 +165,10 @@ public interface JdbcOperations {
* @param sql SQL
* @param rowMapper {@link ResultSet} 中每一行的数据的处理逻辑
*/
<T> Optional<T> queryFirst(String sql, RowMapper<T> rowMapper)
throws SQLException;
default <T> Optional<T> queryFirst(String sql, RowMapper<T> rowMapper)
throws SQLException {
return queryFirst(sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
/**
* 查询第一行第一列,并转换为指定类型
@@ -167,28 +177,40 @@ public interface JdbcOperations {
* @param sql SQL
* @param clazz 目标类型
*/
<T> Optional<T> queryFirst(String sql, Class<T> clazz)
throws SQLException;
default <T> Optional<T> queryFirst(String sql, Class<T> clazz)
throws SQLException {
return queryFirst(sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz);
}
/**
* 执行查询,将第一行数据转为 Map<String, Object>
*
* @param sql SQL
*/
Optional<Map<String, Object>> queryFirst(String sql)
throws SQLException;
default Optional<Map<String, Object>> queryFirst(String sql)
throws SQLException {
return queryFirst(sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
/**
* 查询第一行第一列并转换为 boolean
*
* <p>
* <b>注:如果查询结果为空,则返回 {@code false}。</b>
*
* @param sql SQL
*/
boolean queryBoolean(String sql)
throws SQLException;
default boolean queryBoolean(String sql)
throws SQLException {
return queryBoolean(sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
/**
* 查询第一行第一列并转换为 boolean
*
* <p>
* <b>注:如果查询结果为空,则返回 {@code false}。</b>
*
* @param sql SQL
*/
boolean queryBoolean(String sql, Object[] params)
@@ -214,8 +236,10 @@ public interface JdbcOperations {
* @param sql 要执行的 SQL
* @return 更新记录数
*/
int update(String sql)
throws SQLException;
default int update(String sql)
throws SQLException {
return update(sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
/**
* 执行 SQL 并返回生成的 keys
@@ -239,8 +263,10 @@ public interface JdbcOperations {
* @return generated keys
* @throws SQLException 执行 SQL 遇到异常情况将抛出
*/
<T> List<T> update(String sql, RowMapper<T> rowMapper)
throws SQLException;
default <T> List<T> update(String sql, RowMapper<T> rowMapper)
throws SQLException {
return update(sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
/**
* 批量更新
@@ -261,7 +287,6 @@ public interface JdbcOperations {
* @param sql sql语句
* @param params 参数列表
* @param batchSize 每次批量更新的数据量
* @param exceptions 空列表,用于记录异常信息
* @param quietly 静默分批更新。
* 如果 {@code quietly} 为 {@code true},分批更新过程中发生异常不中断操作;
* 如果 {@code quietly} 为 {@code false},分批更新过程中发生异常即中断操作,并返回结果。

View File

@@ -36,13 +36,18 @@ import java.util.Map;
public interface RowMapper<T> {
T mapRow(ResultSet rs, int rowNumber) throws SQLException;
/** 每一行数据转换为 {@link HashMap} */
/**
* 每一行数据转换为 {@link HashMap}
*
* <p>
* <b>注:如果两个属性映射到同一列名(虽然不常见),后者静默覆盖前者。</b>
*/
RowMapper<Map<String, Object>> HASH_MAP_MAPPER = (rs, rowNumber) -> {
Map<String, Object> result = new HashMap<>();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
String colName = metaData.getColumnName(i);
String colName = metaData.getColumnLabel(i);
result.put(colName, rs.getObject(colName));
}
return result;

View File

@@ -61,15 +61,6 @@ public class SimpleJdbcTemplate implements JdbcOperations {
}
}
/** {@inheritDoc} */
@Override
public <T> T query(String sql, ResultHandler<T> resultHandler)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.query(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, resultHandler);
}
}
// #endregion
// #region - queryList
@@ -101,34 +92,6 @@ public class SimpleJdbcTemplate implements JdbcOperations {
}
}
/** {@inheritDoc} */
@Override
public <T> List<T> queryList(String sql, RowMapper<T> rowMapper)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryList(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
}
/** {@inheritDoc} */
@Override
public <T> List<T> queryList(String sql, Class<T> clazz)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryList(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz);
}
}
/** {@inheritDoc} */
@Override
public List<Map<String, Object>> queryList(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport
.queryList(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.HASH_MAP_MAPPER);
}
}
// #endregion
// #region - queryFirst
@@ -166,51 +129,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
/** {@inheritDoc} */
@Override
public <T> Optional<T> queryFirst(String sql, RowMapper<T> rowMapper)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final T result = JdbcOperationSupport
.queryFirst(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
return Optional.ofNullable(result);
}
}
/** {@inheritDoc} */
@Override
public <T> Optional<T> queryFirst(String sql, Class<T> clazz)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final T result = JdbcOperationSupport
.queryFirst(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz);
return Optional.ofNullable(result);
}
}
/** {@inheritDoc} */
@Override
public Optional<Map<String, Object>> queryFirst(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final Map<String, Object> result = JdbcOperationSupport
.queryFirst(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.HASH_MAP_MAPPER);
return Optional.ofNullable(result);
}
}
/** {@inheritDoc} */
@Override
public boolean queryBoolean(String sql) // TODO 单元测试
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final Boolean result = JdbcOperationSupport
.queryFirstBoolean(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
return Boolean.TRUE.equals(result);
}
}
/** {@inheritDoc} */
@Override
public boolean queryBoolean(String sql, Object[] params) // TODO 单元测试
public boolean queryBoolean(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final Boolean result = JdbcOperationSupport
@@ -232,15 +151,6 @@ public class SimpleJdbcTemplate implements JdbcOperations {
}
}
/** {@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 <T> List<T> update(String sql, Object[] params, RowMapper<T> rowMapper)
@@ -250,15 +160,6 @@ public class SimpleJdbcTemplate implements JdbcOperations {
}
}
/** {@inheritDoc} */
@Override
public <T> List<T> update(String sql, RowMapper<T> rowMapper)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.update(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
}
/** {@inheritDoc} */
@Override
public BatchUpdateResult batchUpdate(String sql, @Nullable Collection<Object[]> params, int batchSize)
@@ -271,7 +172,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
/** {@inheritDoc} */
@Override
public BatchUpdateResult batchUpdate(String sql, @Nullable Collection<Object[]> params,
int batchSize, boolean quietly)
int batchSize, boolean quietly)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport
@@ -290,14 +191,14 @@ public class SimpleJdbcTemplate implements JdbcOperations {
* operations 中使用 JdbcExecutor 实参进行 JDBC 操作,这些操作在一个连接中
* </p>
*
* @param <E> 异常类型
* @param operations 事务操作
* @throws SQLException SQL 异常
* @throws E 事务中的异常
* @param <E> 异常类型
* @param operations 事务操作
* @throws SQLException SQL 异常
* @throws TransactionException 事务异常。事务中的异常会包装在该异常中。
*/
public <E extends Exception> void executeTransaction(
@Nonnull final ThrowingConsumer<JdbcOperations, E> operations)
throws SQLException, E {
throws TransactionException, SQLException {
AssertTools.checkNotNull(operations, "Operations can not be null.");
try (Connection conn = this.dataSource.getConnection()) {
final boolean autoCommit = conn.getAutoCommit();
@@ -305,12 +206,10 @@ public class SimpleJdbcTemplate implements JdbcOperations {
conn.setAutoCommit(false);
operations.accept(new JdbcExecutor(conn));
conn.commit();
}
catch (Exception e) {
} catch (Exception e) {
conn.rollback();
throw new SQLException("Transaction failed during execution", e);
}
finally {
throw new TransactionException(e);
} finally {
conn.setAutoCommit(autoCommit);
}
}
@@ -321,14 +220,14 @@ public class SimpleJdbcTemplate implements JdbcOperations {
* 如果 {@code operations} 返回 {@code true},则提交事务;
* 如果抛出异常,或返回 {@code false},则回滚事务
*
* @param <E> 事务中的异常
* @param operations 事务操作
* @throws SQLException 数据库异常
* @throws E 事务中的异常类型
* @param <E> 事务中的异常
* @param operations 事务操作
* @throws SQLException 数据库异常
* @throws TransactionException 事务异常。事务中的异常会包装在该异常中。
*/
public <E extends Exception> void commitIfTrue(
@Nonnull final ThrowingPredicate<JdbcOperations, E> operations)
throws SQLException, E {
throws SQLException, TransactionException {
AssertTools.checkNotNull(operations, "Operations can not be null.");
try (Connection conn = this.dataSource.getConnection()) {
final boolean autoCommit = conn.getAutoCommit();
@@ -336,16 +235,13 @@ public class SimpleJdbcTemplate implements JdbcOperations {
conn.setAutoCommit(false);
if (operations.test(new JdbcExecutor(conn))) {
conn.commit();
}
else {
} else {
conn.rollback();
}
}
catch (Exception e) {
} catch (Exception e) {
conn.rollback();
throw new SQLException("Transaction failed during execution", e);
}
finally {
throw new TransactionException(e);
} finally {
conn.setAutoCommit(autoCommit);
}
}
@@ -370,14 +266,6 @@ public class SimpleJdbcTemplate implements JdbcOperations {
return JdbcOperationSupport.query(this.conn, sql, params, resultHandler);
}
/** {@inheritDoc} */
@Override
public <T> T query(String sql, ResultHandler<T> resultHandler)
throws SQLException {
return JdbcOperationSupport
.query(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, resultHandler);
}
// #endregion
// #region - queryList
@@ -403,29 +291,6 @@ public class SimpleJdbcTemplate implements JdbcOperations {
return JdbcOperationSupport.queryList(this.conn, sql, params, RowMapper.HASH_MAP_MAPPER);
}
/** {@inheritDoc} */
@Override
public <T> List<T> queryList(String sql, RowMapper<T> rowMapper)
throws SQLException {
return JdbcOperationSupport
.queryList(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
/** {@inheritDoc} */
@Override
public <T> List<T> queryList(String sql, Class<T> clazz)
throws SQLException {
return JdbcOperationSupport.queryList(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz);
}
/** {@inheritDoc} */
@Override
public List<Map<String, Object>> queryList(String sql)
throws SQLException {
return JdbcOperationSupport
.queryList(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.HASH_MAP_MAPPER);
}
// #endregion
// #region - queryFirst
@@ -455,42 +320,6 @@ public class SimpleJdbcTemplate implements JdbcOperations {
return Optional.ofNullable(result);
}
/** {@inheritDoc} */
@Override
public <T> Optional<T> queryFirst(String sql, RowMapper<T> rowMapper)
throws SQLException {
final T result = JdbcOperationSupport
.queryFirst(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
return Optional.ofNullable(result);
}
/** {@inheritDoc} */
@Override
public <T> Optional<T> queryFirst(String sql, Class<T> clazz)
throws SQLException {
final T result = JdbcOperationSupport
.queryFirst(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz);
return Optional.ofNullable(result);
}
/** {@inheritDoc} */
@Override
public Optional<Map<String, Object>> queryFirst(String sql)
throws SQLException {
final Map<String, Object> result = JdbcOperationSupport
.queryFirst(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.HASH_MAP_MAPPER);
return Optional.ofNullable(result);
}
/** {@inheritDoc} */
@Override
public boolean queryBoolean(String sql)
throws SQLException {
final Boolean result = JdbcOperationSupport
.queryFirstBoolean(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
return Boolean.TRUE.equals(result);
}
/** {@inheritDoc} */
@Override
public boolean queryBoolean(String sql, Object[] params)
@@ -510,13 +339,6 @@ public class SimpleJdbcTemplate implements JdbcOperations {
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 <T> List<T> update(String sql, Object[] params, RowMapper<T> rowMapper)
@@ -524,13 +346,6 @@ public class SimpleJdbcTemplate implements JdbcOperations {
return JdbcOperationSupport.update(this.conn, sql, params, rowMapper);
}
/** {@inheritDoc} */
@Override
public <T> List<T> update(String sql, RowMapper<T> rowMapper)
throws SQLException {
return JdbcOperationSupport.update(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
/** {@inheritDoc} */
@Override
public BatchUpdateResult batchUpdate(String sql, @Nullable Collection<Object[]> params, int batchSize)
@@ -541,9 +356,9 @@ public class SimpleJdbcTemplate implements JdbcOperations {
/** {@inheritDoc} */
@Override
public BatchUpdateResult batchUpdate(String sql,
@Nullable Collection<Object[]> params,
int batchSize,
boolean quietly) throws SQLException {
@Nullable Collection<Object[]> params,
int batchSize,
boolean quietly) throws SQLException {
return JdbcOperationSupport
.batchUpdate(this.conn, sql, params, batchSize, quietly);
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2026 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;
/**
* 事务异常
*
* <p>
* 用于包装事务执行过程中发生的原始异常
*
* @author ZhouXY108 <luquanlion@outlook.com>
*/
public class TransactionException extends Exception {
private static final long serialVersionUID = 87276230526383501L;
/**
* 事务异常
*
* @param cause 原始异常
*/
public TransactionException(Throwable cause) {
super("Transaction failed during execution", cause);
}
/**
* 事务异常
*
* @param message 异常信息
* @param cause 原始异常
*/
public TransactionException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -42,6 +42,7 @@ import com.google.common.io.Resources;
import xyz.zhouxy.jdbc.JdbcOperations;
import xyz.zhouxy.jdbc.RowMapper;
import xyz.zhouxy.jdbc.SimpleJdbcTemplate;
import xyz.zhouxy.jdbc.TransactionException;
import xyz.zhouxy.plusone.commons.util.IdGenerator;
import xyz.zhouxy.plusone.commons.util.IdWorker;
@@ -146,20 +147,18 @@ class SimpleJdbcTemplateTests {
}
@Test
void testTransaction() throws SQLException {
void testTransaction() throws TransactionException, SQLException {
// 抛异常,回滚
{
long id = this.idGenerator.nextId();
try {
TransactionException e = assertThrows(TransactionException.class, () -> {
jdbcTemplate.executeTransaction((JdbcOperations jdbc) -> {
jdbc.update("INSERT INTO sys_account (id, username, created_by, create_time, account_status) VALUES (?, ?, ?, ?, ?)",
buildParams(id, "testTransaction1", 100, LocalDateTime.now(), "55"));
throw new NullPointerException();
});
}
catch (NullPointerException e) {
// ignore
}
});
assertEquals(NullPointerException.class, e.getCause().getClass());
Optional<Map<String, Object>> first = jdbcTemplate
.queryFirst("SELECT * FROM sys_account WHERE id = ?", buildParams(id));
log.info("first: {}", first);
@@ -183,16 +182,14 @@ class SimpleJdbcTemplateTests {
// 抛异常,回滚
{
long id = this.idGenerator.nextId();
try {
TransactionException e = assertThrows(TransactionException.class, () -> {
jdbcTemplate.commitIfTrue(jdbc -> {
jdbc.update("INSERT INTO sys_account (id, username, created_by, create_time, account_status) VALUES (?, ?, ?, ?, ?)",
buildParams(id, "testTransaction3", 102, LocalDateTime.now(), "55"));
throw new NullPointerException();
});
}
catch (NullPointerException e) {
// ignore
}
});
assertEquals(NullPointerException.class, e.getCause().getClass());
Optional<Map<String, Object>> first = jdbcTemplate
.queryFirst("SELECT * FROM sys_account WHERE id = ?", buildParams(id));
log.info("first: {}", first);
@@ -244,4 +241,15 @@ class SimpleJdbcTemplateTests {
t.get());
log.info("{}", t);
}
@Test
void testQueryBoolean() throws SQLException {
// 建议写法
assertTrue(jdbcTemplate.queryBoolean("SELECT EXISTS(SELECT 1 FROM sys_account WHERE id = 10)"));
assertFalse(jdbcTemplate.queryBoolean("SELECT EXISTS(SELECT 1 FROM sys_account WHERE id = 999)"));
// 不建议写法
assertTrue(jdbcTemplate.queryBoolean("SELECT 1 FROM sys_account WHERE id = 10"));
assertFalse(jdbcTemplate.queryBoolean("SELECT 1 FROM sys_account WHERE id = 999"));
}
}

View File

@@ -1,3 +1,5 @@
DROP TABLE IF EXISTS sys_account;
CREATE TABLE sys_account (
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
, `username` VARCHAR(255) NOT NULL
@@ -7,4 +9,4 @@ CREATE TABLE sys_account (
, `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
, `updated_by` BIGINT DEFAULT NULL
, `version` BIGINT NOT NULL DEFAULT 0
)
);