Compare commits

..

1 Commits

Author SHA1 Message Date
42af67b651 1.0.0-alpha
Reviewed-on: http://zhouxy.xyz:3000/ZhouXY108/simple-jdbc/pulls/1
2024-11-02 11:41:50 +08:00
21 changed files with 567 additions and 732 deletions

View File

@@ -10,9 +10,3 @@ end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.sql]
indent_size = 2
[*.md]
indent_size = 2

5
.gitignore vendored
View File

@@ -4,7 +4,10 @@ target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr

3
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# 默认忽略的文件
/shelf/
/workspace.xml

7
.idea/encodings.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

View File

@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="NonSerializableWithSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

14
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

179
README.md
View File

@@ -1,181 +1,6 @@
# SimpleJDBC
对 JDBC 的简单封装。
之前遇到的一个老项目,没有引入任何 ORM 框架,对数据库的操作几乎都在写原生 JDBC。故自己写了几个工具类对 JDBC 进行简单封装。
之前遇到的一个老项目,没有引入任何 ORM 框架,使用的 JDK7 明明支持泛型,所依赖的 spring-jdbc 居然是没有泛型的远古版本,该项目又不允许随意添加依赖,对数据库的操作几乎都在写原生 JDBC。故自己写了几个工具类对 JDBC 进行简单封装,后来逐渐改进完善
## 查询
### 查询方法
- `query`**最基础的查询方法**。可使用 `ResultHandler` 将查询结果映射为 Java 对象。
- `queryList`**查询列表**。可使用 `RowMapper` 将结果的每一行数据映射为 Java 对象,返回列表。
- `queryFirst`**查询,并获取第一行数据**。一般可以结合 `LIMIT 1` 使用。可使用 `RowMapper` 将结果的第一行数据映射为 Java 对象,返回 `Optional`
- `queryFirstXXX`**查询,并获取第一行数据的第一个字段**,并转换为对应类型,返回对应的类型的 `Optional`
- `queryAsBoolean`**查询,并获取第一行数据的第一个字段**,并转换为布尔类型。如果结果为空,则返回 `false`
### 结果映射
- `ResultHandler` 用于处理查询结果,自定义逻辑将完整的 `ResultSet` 映射为 Java 对象。 *结果可以是任意类型(包括集合)。*
- `RowMapper` 用于将 `ResultSet` 中的一行数据映射为 Java 对象。
- `RowMapper#HASH_MAP_MAPPER`:将 `ResultSet` 中的一行数据映射为 `HashMap`
- `RowMapper#beanRowMapper`:返回将 `ResultSet` 转换为 Java Bean 的默认实现。
## 更新
- `int update`**执行 DML**,包括 `INSERT``UPDATE``DELETE` 等。返回受影响行数。
- `<T> List<T> update`**执行 DML**,自动生成的字段将使用 `rowMapper` 进行映射,并返回列表。
- `List<int[]> batchUpdate`**分批次执行 DML**,返回每个批次的每条 SQL 语句影响的行数。
- `List<int[]> batchUpdateAndIgnoreException`**分批次执行 DML如果某个批次出现异常继续执行下一个批次**。返回每个批次的每条 SQL 语句影响的行数。
## 事务
- `executeTransaction`**执行事务**。传入一个 `ThrowingConsumer` 函数,入参是一个 `JdbcExecutor` 对象,在 `ThrowingConsumer` 内使用该入参执行 jdbc 操作。如果 `ThrowingConsumer` 内部有异常抛出,这些操作将被回滚。
- `commitIfTrue`**执行事务**。传入一个 `ThrowingPredicate` 函数,入参是一个 `JdbcExecutor` 对象,在 `ThrowingPredicate` 内使用该入参执行 jdbc 操作。如果`ThrowingPredicate` 返回 `true`,则提交事务;如果返回 `false` 或有异常抛出,则回滚这些操作。
## 参数构建
此项目中的所有查询和更新的方法,都**不使用可变长入参**,避免强行将 SQL 语句的参数列表放在最后,也避免和数组发生歧义。
### 构建参数列表
可使用 `ParamBuilder#buildParams` 构建 `Object[]` 数组作为 SQL 的参数列表。该方法会自动将 `Optional` 中的值“拆”出来。
### 批量构建参数列表
使用 `ParamBuilder#buildBatchParams`,将使用传入的函数,将集合中的每一个元素转为 `Object[]`,并返回一个 `List<Object[]>`
## 示例
创建 SimpleJdbcTemplate 对象
```java
SimpleJdbcTemplate jdbcTemplate = new SimpleJdbcTemplate(dataSource);
```
查询
```java
// 查询
List<Account> list = jdbcTemplate.query(
"SELECT * FROM account WHERE deleted = 0 AND username LIKE ? AND org_no = ?",
buildParams("admin%", "0000"),
rs -> {
List<T> result = new ArrayList<>();
while (rs.next()) {
result.add(new Account(
rs.getLong("id"),
rs.getString("username"),
rs.getString("password"),
rs.getString("org_no"),
rs.getTimestamp("create_time"),
rs.getTimestamp("update_time")
));
}
return result;
}
);
// 查询列表
List<Account> list = jdbcTemplate.queryList(
"SELECT * FROM account WHERE deleted = 0 AND username LIKE ? AND org_no = ?",
buildParams("admin%", "0000"),
(rs, rowNum) -> new Account(
rs.getLong("id"),
rs.getString("username"),
rs.getString("password"),
rs.getString("org_no"),
rs.getTimestamp("create_time"),
rs.getTimestamp("update_time")
)
);
// 查询一行数据
Optional<Account> account = jdbcTemplate.queryFirst(
"SELECT * FROM account WHERE deleted = 0 AND id = ?",
buildParams(10000L),
(rs, rowNum) -> new Account(
rs.getLong("id"),
rs.getString("username"),
rs.getString("password"),
rs.getString("org_no"),
rs.getTimestamp("create_time"),
)
)
// 查询一行数据,并获取第一个字段
OptionalInt age = jdbcTemplate.queryFirstInt(
"SELECT age FROM view_account WHERE deleted = 0 AND id = ?",
buildParams(10000L)
);
// 查询 boolean
boolean exists = jdbcTemplate.queryAsBoolean(
"SELECT EXISTS(SELECT 1 FROM account WHERE deleted = 0 AND id = ? LIMIT 1)",
buildParams(10000L)
);
```
更新
```java
// 执行 DML
int affectedRows = jdbcTemplate.update(
"UPDATE account SET deleted = 1 WHERE id = ?",
buildParams(10000L)
);
// 执行 DML并获取生成的主键
List<Pair<Long, LocalDateTime>> keys = jdbcTemplate.update(
"INSERT INTO account (username, password, org_no) VALUES (?, ?, ?)",
buildParams("admin", "123456", "0000"),
(rs, rowNum) -> Pair.of(
rs.getLong("id"),
rs.getObject("create_time", LocalDateTime.class)
)
);
```
批量更新
```java
jdbcTemplate.batchUpdate(
"INSERT INTO account (username, password, org_no) VALUES (?, ?, ?)",
buildBatchParams(accountList, account -> buildParams(
account.getUsername(),
account.getPassword(),
account.getOrgNo()
)),
100 // 每100条数据一个批次
);
```
事务
```java
jdbcTemplate.executeTransaction(jdbc -> {
...
jdbc.update(...);
...
jdbc.update(...);
...
});
jdbcTemplate.commitIfTrue(jdbc -> {
...
jdbc.update(...);
...
if (...) {
// 中断操作并回滚
return false;
}
...
if (...) {
// 某些条件下提前结束并提交事务
return true;
}
...
jdbc.update(...);
...
// 提交事务
return true;
});
```
>**!!!本项目不比成熟的工具,如若使用请自行承担风险。建议仅作为 JDBC 的学习参考。**
本项目不比成熟的工具,如若使用请自行承担风险。建议仅作为 JDBC 的学习参考。

25
pom.xml
View File

@@ -8,46 +8,30 @@
<artifactId>simple-jdbc</artifactId>
<version>1.0.0-alpha</version>
<name>Simple JDBC</name>
<description>对 JDBC 的简单封装。</description>
<url>http://gitea.zhouxy.xyz/plusone/simple-jdbc</url>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<plusone-commons.version>1.1.0-RC1</plusone-commons.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>xyz.zhouxy.plusone</groupId>
<artifactId>plusone-dependencies</artifactId>
<version>${plusone-commons.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>xyz.zhouxy.plusone</groupId>
<artifactId>plusone-commons</artifactId>
<version>${plusone-commons.version}</version>
<version>1.0.0-alpha</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
<scope>test</scope>
</dependency>
@@ -55,6 +39,7 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.2.224</version>
<scope>test</scope>
</dependency>
</dependencies>

View File

@@ -0,0 +1,106 @@
/*
* 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.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 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;
/**
* DbRecord
*
* <p>
* 封装 Map<String, Object>,表示一条 DB 记录
* </p>
*
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
* @since 1.0.0
*/
@Beta
public class DbRecord extends AbstractMapWrapper<String, Object, DbRecord> {
public DbRecord() {
super(new HashMap<>(),
k -> AssertTools.checkArgument(StringTools.isNotBlank(k), "Key must has text."),
null);
}
public DbRecord(Map<String, Object> map) {
super(map,
k -> AssertTools.checkArgument(StringTools.isNotBlank(k), "Key must has text."),
null);
}
/**
* 将值强转为 {@link String},并放在 {@link Optional} 中。
* 如果 {@code key} 存在,而值不存在,则返回 {@link Optional#empty()}。
*/
public Optional<String> getValueAsString(String key) {
return this.getAndConvert(key);
}
/**
* 将值强转为 {@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));
}
@Override
protected DbRecord getSelf() {
return this;
}
private static final String STR_PREFIX = DbRecord.class.getName() + '@';
@Override
public String toString() {
return STR_PREFIX + super.toString();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2022-2025 the original author or authors.
* 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.
@@ -48,7 +48,7 @@ import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
* <b>NOTE: 使用反射获取类型信息,也是使用反射调用无参构造器和 {@code setter} 方法。
* 实际使用中还是建议针对目标类型自定义 {@link RowMapper}。</b>
* </p>
* @author ZhouXY108 <luquanlion@outlook.com>
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
* @since 1.0.0
*/
public class DefaultBeanRowMapper<T> implements RowMapper<T> {
@@ -65,12 +65,12 @@ public class DefaultBeanRowMapper<T> implements RowMapper<T> {
}
/**
* 创建一个 {@code DefaultBeanRowMapper}
* 创建一个 DefaultBeanRowMapper
*
* @param <T> Bean 类型
* @param beanType Bean 类型
* @return DefaultBeanRowMapper 对象
* @throws SQLException 创建 {@code DefaultBeanRowMapper} 出现错误的异常时抛出
* @throws SQLException 创建 DefaultBeanRowMapper 出现错误的异常时抛出
*/
@StaticFactoryMethod(DefaultBeanRowMapper.class)
public static <T> DefaultBeanRowMapper<T> of(Class<T> beanType) throws SQLException {
@@ -78,13 +78,13 @@ public class DefaultBeanRowMapper<T> implements RowMapper<T> {
}
/**
* 创建一个 {@code DefaultBeanRowMapper}
* 创建一个 DefaultBeanRowMapper
*
* @param <T> Bean 类型
* @param beanType Bean 类型
* @param propertyColMap Bean 字段与列名的映射关系。key 是字段value 是列名。
* @return {@code DefaultBeanRowMapper} 对象
* @throws SQLException 创建 {@code DefaultBeanRowMapper} 出现错误的异常时抛出
* @return DefaultBeanRowMapper 对象
* @throws SQLException 创建 DefaultBeanRowMapper 出现错误的异常时抛出
*/
@StaticFactoryMethod(DefaultBeanRowMapper.class)
public static <T> DefaultBeanRowMapper<T> of(Class<T> beanType, @Nullable Map<String, String> propertyColMap)
@@ -94,7 +94,25 @@ public class DefaultBeanRowMapper<T> implements RowMapper<T> {
Constructor<T> constructor = beanType.getDeclaredConstructor();
constructor.setAccessible(true); // NOSONAR
final Map<String, PropertyDescriptor> colPropertyMap = buildColPropertyMap(beanType, propertyColMap);
// 构建 column name 和 PropertyDescriptor 的 映射
BeanInfo beanInfo = Introspector.getBeanInfo(beanType);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
// Bean 的属性名为小驼峰,对应的列名为下划线
Function<? super PropertyDescriptor, String> keyMapper;
if (propertyColMap == null || propertyColMap.isEmpty()) {
keyMapper = p -> CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, p.getName());
}
else {
keyMapper = p -> {
String propertyName = p.getName();
String colName = propertyColMap.get(propertyName);
return colName != null ? colName
: CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, propertyName);
};
}
Map<String, PropertyDescriptor> colPropertyMap = Arrays.stream(propertyDescriptors).collect(
Collectors.toMap(keyMapper, Function.identity(), (a, b) -> b));
return new DefaultBeanRowMapper<>(constructor, colPropertyMap);
}
catch (IntrospectionException e) {
@@ -132,36 +150,4 @@ public class DefaultBeanRowMapper<T> implements RowMapper<T> {
throw new SQLException(e);
}
}
/**
* 构建 column name 和 PropertyDescriptor 的 映射
*
* @param <T> Java bean 类型
* @param beanType Java bean 类型
* @param propertyColMap 属性与列名的映射
* @return column name 和 PropertyDescriptor 的映射
* @throws IntrospectionException if an exception occurs during introspection.
*/
private static <T> Map<String, PropertyDescriptor> buildColPropertyMap(
Class<T> beanType, Map<String, String> propertyColMap) throws IntrospectionException {
BeanInfo beanInfo = Introspector.getBeanInfo(beanType);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
// Bean 的属性名为小驼峰,对应的列名为下划线
Function<? super PropertyDescriptor, String> keyMapper;
if (propertyColMap == null || propertyColMap.isEmpty()) {
keyMapper = p -> CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, p.getName());
}
else {
keyMapper = p -> {
String propertyName = p.getName();
String colName = propertyColMap.get(propertyName);
return colName != null ? colName
: CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, propertyName);
};
}
return Arrays.stream(propertyDescriptors)
.collect(Collectors.toMap(keyMapper, Function.identity(), (a, b) -> b));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2024-2025 the original author or authors.
* Copyright 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.
@@ -26,7 +26,10 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.OptionalLong;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -35,6 +38,7 @@ import com.google.common.collect.Lists;
import xyz.zhouxy.plusone.commons.collection.CollectionTools;
import xyz.zhouxy.plusone.commons.util.AssertTools;
import xyz.zhouxy.plusone.commons.util.OptionalTools;
/**
* JdbcOperationSupport
@@ -43,7 +47,7 @@ import xyz.zhouxy.plusone.commons.util.AssertTools;
* 提供静态方法,封装 JDBC 基础操作
* </p>
*
* @author ZhouXY108 <luquanlion@outlook.com>
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
* @since 1.0.0
*/
class JdbcOperationSupport {
@@ -107,14 +111,14 @@ class JdbcOperationSupport {
// #region - queryFirst
/**
* 执行查询,将查询结果的第一行数据按照指定逻辑进行映射
* 执行查询,将查询结果的第一行数据按照指定逻辑进行处理,返回 {@link Optional}
*
* @param conn 数据库连接
* @param sql SQL
* @param params 参数
* @param rowMapper {@link ResultSet} 中每一行的数据的处理逻辑
*/
static <T> T queryFirst(Connection conn, String sql, Object[] params, RowMapper<T> rowMapper)
static <T> Optional<T> queryFirst(Connection conn, String sql, Object[] params, RowMapper<T> rowMapper)
throws SQLException {
assertConnectionNotNull(conn);
assertSqlNotNull(sql);
@@ -130,7 +134,7 @@ class JdbcOperationSupport {
* @param params 参数
* @param clazz 目标类型
*/
static <T> T queryFirst(Connection conn, String sql, Object[] params, Class<T> clazz)
static <T> Optional<T> queryFirst(Connection conn, String sql, Object[] params, Class<T> clazz)
throws SQLException {
assertConnectionNotNull(conn);
assertSqlNotNull(sql);
@@ -145,7 +149,7 @@ class JdbcOperationSupport {
* @param sql SQL
* @param params 参数
*/
static String queryFirstString(Connection conn, String sql, Object[] params)
static Optional<String> queryFirstString(Connection conn, String sql, Object[] params)
throws SQLException {
return queryFirst(conn, sql, params, (rs, rowNumber) -> rs.getString(1));
}
@@ -157,9 +161,10 @@ class JdbcOperationSupport {
* @param sql SQL
* @param params 参数
*/
static Integer queryFirstInt(Connection conn, String sql, Object[] params)
static OptionalInt queryFirstInt(Connection conn, String sql, Object[] params)
throws SQLException {
return queryFirst(conn, sql, params, (rs, rowNumber) -> rs.getInt(1));
Optional<Integer> result = queryFirst(conn, sql, params, (rs, rowNumber) -> rs.getInt(1));
return OptionalTools.toOptionalInt(result);
}
/**
@@ -169,9 +174,10 @@ class JdbcOperationSupport {
* @param sql SQL
* @param params 参数
*/
static Long queryFirstLong(Connection conn, String sql, Object[] params)
static OptionalLong queryFirstLong(Connection conn, String sql, Object[] params)
throws SQLException {
return queryFirst(conn, sql, params, (rs, rowNumber) -> rs.getLong(1));
Optional<Long> result = queryFirst(conn, sql, params, (rs, rowNumber) -> rs.getLong(1));
return OptionalTools.toOptionalLong(result);
}
/**
@@ -181,9 +187,10 @@ class JdbcOperationSupport {
* @param sql SQL
* @param params 参数
*/
static Double queryFirstDouble(Connection conn, String sql, Object[] params)
static OptionalDouble queryFirstDouble(Connection conn, String sql, Object[] params)
throws SQLException {
return queryFirst(conn, sql, params, (rs, rowNumber) -> rs.getDouble(1));
Optional<Double> result = queryFirst(conn, sql, params, (rs, rowNumber) -> rs.getDouble(1));
return OptionalTools.toOptionalDouble(result);
}
/**
@@ -193,23 +200,11 @@ class JdbcOperationSupport {
* @param sql SQL
* @param params 参数
*/
static BigDecimal queryFirstBigDecimal(Connection conn, String sql, Object[] params)
static Optional<BigDecimal> queryFirstBigDecimal(Connection conn, String sql, Object[] params)
throws SQLException {
return queryFirst(conn, sql, params, (rs, rowNumber) -> rs.getBigDecimal(1));
}
/**
* 查询结果,并转换为 bool 值
*
* @param conn 数据库连接
* @param sql SQL
* @param params 参数
*/
static Boolean queryFirstBoolean(Connection conn, String sql, Object[] params)
throws SQLException {
return queryFirst(conn, sql, params, (rs, rowNumber) -> rs.getBoolean(1));
}
// #endregion
// #region - update & batchUpdate
@@ -252,7 +247,7 @@ class JdbcOperationSupport {
try (PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
fillStatement(stmt, params);
stmt.executeUpdate();
try (ResultSet generatedKeys = stmt.getGeneratedKeys()) {
try (ResultSet generatedKeys = stmt.getGeneratedKeys();) {
int rowNumber = 0;
while (generatedKeys.next()) {
T e = rowMapper.mapRow(generatedKeys, rowNumber++);
@@ -362,9 +357,9 @@ class JdbcOperationSupport {
* @param resultHandler 结果处理器,用于处理 {@link ResultSet}
*/
private static <T> T queryInternal(@Nonnull Connection conn,
@Nonnull String sql,
@Nullable Object[] params,
@Nonnull ResultHandler<T> resultHandler)
@Nonnull String sql,
@Nullable Object[] params,
@Nonnull ResultHandler<T> resultHandler)
throws SQLException {
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
fillStatement(stmt, params);
@@ -383,9 +378,9 @@ class JdbcOperationSupport {
* @param rowMapper {@link ResultSet} 中每一行的数据的处理逻辑
*/
private static <T> List<T> queryListInternal(@Nonnull Connection conn,
@Nonnull String sql,
@Nullable Object[] params,
@Nonnull RowMapper<T> rowMapper)
@Nonnull String sql,
@Nullable Object[] params,
@Nonnull RowMapper<T> rowMapper)
throws SQLException {
return queryInternal(conn, sql, params, rs -> {
List<T> result = new ArrayList<>();
@@ -399,21 +394,24 @@ class JdbcOperationSupport {
}
/**
* 执行查询,将查询结果的第一行数据按照指定逻辑进行处理,返回映射结果
* 执行查询,将查询结果的第一行数据按照指定逻辑进行处理,返回 {@link Optional}
*
* @param conn 数据库连接
* @param sql SQL
* @param params 参数
* @param rowMapper 行数据映射逻辑
* @return 映射结果。如果查询结果为空,则返回 null
*/
private static <T> T queryFirstInternal(@Nonnull Connection conn,
private static <T> Optional<T> queryFirstInternal(@Nonnull Connection conn,
@Nonnull String sql,
@Nullable Object[] params,
@Nonnull RowMapper<T> rowMapper)
throws SQLException {
return queryInternal(conn, sql, params, rs ->
rs.next() ? rowMapper.mapRow(rs, 0) : null);
return queryInternal(conn, sql, params, rs -> {
if (rs.next()) {
return Optional.ofNullable(rowMapper.mapRow(rs, 0));
}
return Optional.empty();
});
}
// #endregion
@@ -446,28 +444,23 @@ class JdbcOperationSupport {
// #region - 参数校验
private static void assertConnectionNotNull(Connection conn) {
AssertTools.checkArgument(Objects.nonNull(conn),
"The argument \"conn\" could not be null.");
AssertTools.checkArgumentNotNull(conn, "The argument \"conn\" could not be null.");
}
private static void assertSqlNotNull(String sql) {
AssertTools.checkArgument(Objects.nonNull(sql),
"The argument \"sql\" could not be null.");
AssertTools.checkArgumentNotNull(sql, "The argument \"sql\" could not be null.");
}
private static void assertRowMapperNotNull(RowMapper<?> rowMapper) {
AssertTools.checkArgument(Objects.nonNull(rowMapper),
"The argument \"rowMapper\" could not be null.");
AssertTools.checkArgumentNotNull(rowMapper, "The argument \"rowMapper\" could not be null.");
}
private static void assertResultHandlerNotNull(ResultHandler<?> resultHandler) {
AssertTools.checkArgument(Objects.nonNull(resultHandler),
"The argument \"resultHandler\" could not be null.");
AssertTools.checkArgumentNotNull(resultHandler, "The argument \"resultHandler\" could not be null.");
}
private static void assertClazzNotNull(Class<?> clazz) {
AssertTools.checkArgument(Objects.nonNull(clazz),
"The argument \"clazz\" could not be null.");
AssertTools.checkArgumentNotNull(clazz, "The argument \"clazz\" could not be null.");
}
// #endregion

View File

@@ -1,19 +1,3 @@
/*
* Copyright 2024-2025 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;
@@ -36,7 +20,7 @@ import javax.annotation.Nullable;
* 定义 JdbcTemplate 的 API
* </p>
*
* @author ZhouXY108 <luquanlion@outlook.com>
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
* @since 1.0.0
*/
interface JdbcOperations {
@@ -95,6 +79,15 @@ interface JdbcOperations {
List<Map<String, Object>> queryList(String sql, Object[] params)
throws SQLException;
/**
* 执行查询,每一行数据映射为 {@link DbRecord},返回结果列表
*
* @param sql SQL
* @param params 参数列表
*/
List<DbRecord> queryRecordList(String sql, Object[] params)
throws SQLException;
/**
* 执行查询,将查询结果的每一行数据按照指定逻辑进行处理,返回结果列表
*
@@ -121,6 +114,14 @@ interface JdbcOperations {
List<Map<String, Object>> queryList(String sql)
throws SQLException;
/**
* 执行查询,每一行数据映射为 {@link DbRecord},返回结果列表
*
* @param sql SQL
*/
List<DbRecord> queryRecordList(String sql)
throws SQLException;
// #endregion
// #region - queryFirst
@@ -155,6 +156,15 @@ interface JdbcOperations {
Optional<Map<String, Object>> queryFirst(String sql, Object[] params)
throws SQLException;
/**
* 执行查询,将第一行数据转为 DbRecord
*
* @param sql SQL
* @param params 参数
*/
Optional<DbRecord> queryFirstRecord(String sql, Object[] params)
throws SQLException;
/**
* 查询第一行第一列,并转换为字符串
*
@@ -227,6 +237,14 @@ interface JdbcOperations {
Optional<Map<String, Object>> queryFirst(String sql)
throws SQLException;
/**
* 执行查询,将第一行数据转为 DbRecord
*
* @param sql SQL
*/
Optional<DbRecord> queryFirstRecord(String sql)
throws SQLException;
/**
* 查询第一行第一列,并转换为字符串
*
@@ -267,22 +285,6 @@ interface JdbcOperations {
Optional<BigDecimal> queryFirstBigDecimal(String sql)
throws SQLException;
/**
* 查询结果,并转换为 boolean
*
* @param sql SQL
*/
boolean queryAsBoolean(String sql)
throws SQLException;
/**
* 查询结果,并转换为 boolean
*
* @param sql SQL
*/
boolean queryAsBoolean(String sql, Object[] params)
throws SQLException;
// #endregion
// #region - update & batchUpdate

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2022-2025 the original author or authors.
* 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.
@@ -16,7 +16,6 @@
package xyz.zhouxy.jdbc;
import java.sql.PreparedStatement;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -27,7 +26,6 @@ import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import xyz.zhouxy.plusone.commons.collection.CollectionTools;
import xyz.zhouxy.plusone.commons.util.ArrayTools;
@@ -41,40 +39,29 @@ import xyz.zhouxy.plusone.commons.util.OptionalTools;
* JDBC 参数构造器,将数据转换为 {@code Object[]} 类型,以传给 {@link PreparedStatement}
* </p>
*
* @author ZhouXY108 <luquanlion@outlook.com>
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
* @since 1.0.0
*/
public class ParamBuilder {
public static final Object[] EMPTY_OBJECT_ARRAY = {};
public static Object[] buildParams(final Object... params) {
if (ArrayTools.isEmpty(params)) {
if (ArrayTools.isNullOrEmpty(params)) {
return EMPTY_OBJECT_ARRAY;
}
return buildParamsFromStream(Arrays.stream(params));
}
public static Object[] buildParams(final Collection<?> params) {
if (CollectionTools.isEmpty(params)) {
return EMPTY_OBJECT_ARRAY;
}
return buildParamsFromStream(params.stream());
}
private static Object[] buildParamsFromStream(Stream<?> stream) {
return stream
return Arrays.stream(params)
.map(param -> {
if (param instanceof Optional) {
return OptionalTools.orElseNull((Optional<?>) param);
}
if (param instanceof OptionalInt) {
return OptionalTools.toInteger((OptionalInt) param);
return OptionalTools.toInteger(((OptionalInt) param));
}
if (param instanceof OptionalLong) {
return OptionalTools.toLong((OptionalLong) param);
return OptionalTools.toLong(((OptionalLong) param));
}
if (param instanceof OptionalDouble) {
return OptionalTools.toDouble((OptionalDouble) param);
return OptionalTools.toDouble(((OptionalDouble) param));
}
return param;
})

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2024-2025 the original author or authors.
* Copyright 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.
@@ -26,7 +26,7 @@ import java.sql.SQLException;
* 处理 {@link ResultSet}
* </p>
*
* @author ZhouXY108 <luquanlion@outlook.com>
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
* @since 1.0.0
*/
@FunctionalInterface

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2022-2025 the original author or authors.
* 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.
@@ -29,7 +29,7 @@ import java.util.Map;
* {@link ResultSet} 中每一行数据的处理逻辑。
* </p>
*
* @author ZhouXY108 <luquanlion@outlook.com>
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
* @since 1.0.0
*/
@FunctionalInterface
@@ -37,7 +37,7 @@ public interface RowMapper<T> {
T mapRow(ResultSet rs, int rowNumber) throws SQLException;
/** 每一行数据转换为 {@link HashMap} */
RowMapper<Map<String, Object>> HASH_MAP_MAPPER = (rs, rowNumber) -> {
public static final RowMapper<Map<String, Object>> HASH_MAP_MAPPER = (rs, rowNumber) -> {
Map<String, Object> result = new HashMap<>();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
@@ -48,13 +48,17 @@ public interface RowMapper<T> {
return result;
};
/** 每一行数据转换为 {@link DbRecord} */
public static final RowMapper<DbRecord> RECORD_MAPPER =
(rs, rowNumber) -> new DbRecord(HASH_MAP_MAPPER.mapRow(rs, rowNumber));
/** 默认实现的将 {@link ResultSet} 转换为 Java Bean 的 {@link RowMapper}。 */
static <T> RowMapper<T> beanRowMapper(Class<T> beanType) throws SQLException {
public static <T> RowMapper<T> beanRowMapper(Class<T> beanType) throws SQLException {
return DefaultBeanRowMapper.of(beanType);
}
/** 默认实现的将 {@link ResultSet} 转换为 Java Bean 的 {@link RowMapper}。 */
static <T> RowMapper<T> beanRowMapper(Class<T> beanType, Map<String, String> propertyColMap)
public static <T> RowMapper<T> beanRowMapper(Class<T> beanType, Map<String, String> propertyColMap)
throws SQLException {
return DefaultBeanRowMapper.of(beanType, propertyColMap);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2022-2025 the original author or authors.
* 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.
@@ -34,7 +34,6 @@ 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;
import xyz.zhouxy.plusone.commons.util.OptionalTools;
/**
* SimpleJdbcTemplate
@@ -43,7 +42,7 @@ import xyz.zhouxy.plusone.commons.util.OptionalTools;
* 对 JDBC 的简单封装,方便数据库操作,支持事务,支持批量操作,支持自定义结果集映射
* </p>
*
* @author ZhouXY108 <luquanlion@outlook.com>
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
* @since 1.0.0
*/
public class SimpleJdbcTemplate implements JdbcOperations {
@@ -107,6 +106,15 @@ public class SimpleJdbcTemplate implements JdbcOperations {
}
}
/** {@inheritDoc} */
@Override
public List<DbRecord> 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 <T> List<T> queryList(String sql, RowMapper<T> rowMapper)
@@ -130,8 +138,16 @@ public class SimpleJdbcTemplate implements JdbcOperations {
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);
return JdbcOperationSupport.queryList(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.HASH_MAP_MAPPER);
}
}
/** {@inheritDoc} */
@Override
public List<DbRecord> queryRecordList(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryList(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.RECORD_MAPPER);
}
}
@@ -144,8 +160,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
public <T> Optional<T> queryFirst(String sql, Object[] params, RowMapper<T> rowMapper)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final T result = JdbcOperationSupport.queryFirst(conn, sql, params, rowMapper);
return Optional.ofNullable(result);
return JdbcOperationSupport.queryFirst(conn, sql, params, rowMapper);
}
}
@@ -154,8 +169,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
public <T> Optional<T> queryFirst(String sql, Object[] params, Class<T> clazz)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final T result = JdbcOperationSupport.queryFirst(conn, sql, params, clazz);
return Optional.ofNullable(result);
return JdbcOperationSupport.queryFirst(conn, sql, params, clazz);
}
}
@@ -164,9 +178,16 @@ public class SimpleJdbcTemplate implements JdbcOperations {
public Optional<Map<String, Object>> queryFirst(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final Map<String, Object> result = JdbcOperationSupport
.queryFirst(conn, sql, params, RowMapper.HASH_MAP_MAPPER);
return Optional.ofNullable(result);
return JdbcOperationSupport.queryFirst(conn, sql, params, RowMapper.HASH_MAP_MAPPER);
}
}
/** {@inheritDoc} */
@Override
public Optional<DbRecord> queryFirstRecord(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirst(conn, sql, params, RowMapper.RECORD_MAPPER);
}
}
@@ -175,8 +196,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
public Optional<String> queryFirstString(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final String result = JdbcOperationSupport.queryFirstString(conn, sql, params);
return Optional.ofNullable(result);
return JdbcOperationSupport.queryFirstString(conn, sql, params);
}
}
@@ -185,8 +205,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
public OptionalInt queryFirstInt(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final Integer result = JdbcOperationSupport.queryFirstInt(conn, sql, params);
return OptionalTools.optionalOf(result);
return JdbcOperationSupport.queryFirstInt(conn, sql, params);
}
}
@@ -195,8 +214,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
public OptionalLong queryFirstLong(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final Long result = JdbcOperationSupport.queryFirstLong(conn, sql, params);
return OptionalTools.optionalOf(result);
return JdbcOperationSupport.queryFirstLong(conn, sql, params);
}
}
@@ -205,8 +223,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
public OptionalDouble queryFirstDouble(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final Double result = JdbcOperationSupport.queryFirstDouble(conn, sql, params);
return OptionalTools.optionalOf(result);
return JdbcOperationSupport.queryFirstDouble(conn, sql, params);
}
}
@@ -215,8 +232,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
public Optional<BigDecimal> queryFirstBigDecimal(String sql, Object[] params)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final BigDecimal result = JdbcOperationSupport.queryFirstBigDecimal(conn, sql, params);
return Optional.ofNullable(result);
return JdbcOperationSupport.queryFirstBigDecimal(conn, sql, params);
}
}
@@ -225,9 +241,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
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);
return JdbcOperationSupport.queryFirst(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
}
@@ -236,9 +250,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
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);
return JdbcOperationSupport.queryFirst(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz);
}
}
@@ -247,9 +259,16 @@ public class SimpleJdbcTemplate implements JdbcOperations {
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);
return JdbcOperationSupport.queryFirst(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.HASH_MAP_MAPPER);
}
}
/** {@inheritDoc} */
@Override
public Optional<DbRecord> queryFirstRecord(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport.queryFirst(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.RECORD_MAPPER);
}
}
@@ -258,9 +277,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
public Optional<String> queryFirstString(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final String result = JdbcOperationSupport.
queryFirstString(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
return Optional.ofNullable(result);
return JdbcOperationSupport.queryFirstString(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
}
@@ -269,9 +286,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
public OptionalInt queryFirstInt(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final Integer result = JdbcOperationSupport
.queryFirstInt(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
return OptionalTools.optionalOf(result);
return JdbcOperationSupport.queryFirstInt(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
}
@@ -280,9 +295,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
public OptionalLong queryFirstLong(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final Long result = JdbcOperationSupport
.queryFirstLong(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
return OptionalTools.optionalOf(result);
return JdbcOperationSupport.queryFirstLong(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
}
@@ -291,9 +304,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
public OptionalDouble queryFirstDouble(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final Double result = JdbcOperationSupport
.queryFirstDouble(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
return OptionalTools.optionalOf(result);
return JdbcOperationSupport.queryFirstDouble(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
}
@@ -302,31 +313,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
public Optional<BigDecimal> queryFirstBigDecimal(String sql)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final BigDecimal result = JdbcOperationSupport
.queryFirstBigDecimal(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
return Optional.ofNullable(result);
}
}
/** {@inheritDoc} */
@Override
public boolean queryAsBoolean(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 queryAsBoolean(String sql, Object[] params) // TODO 单元测试
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
final Boolean result = JdbcOperationSupport
.queryFirstBoolean(conn, sql, params);
return Boolean.TRUE.equals(result);
return JdbcOperationSupport.queryFirstBigDecimal(conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
}
@@ -385,8 +372,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
int batchSize, List<Exception> exceptions)
throws SQLException {
try (Connection conn = this.dataSource.getConnection()) {
return JdbcOperationSupport
.batchUpdateAndIgnoreException(conn, sql, params, batchSize, exceptions);
return JdbcOperationSupport.batchUpdateAndIgnoreException(conn, sql, params, batchSize, exceptions);
}
}
@@ -406,8 +392,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
* @throws SQLException SQL 异常
* @throws E 事务中的异常
*/
public <E extends Exception> void executeTransaction(
@Nonnull final ThrowingConsumer<JdbcExecutor, E> operations)
public <E extends Exception> void executeTransaction(@Nonnull final ThrowingConsumer<JdbcExecutor, E> operations)
throws SQLException, E {
AssertTools.checkNotNull(operations, "Operations can not be null.");
try (Connection conn = this.dataSource.getConnection()) {
@@ -437,8 +422,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
* @throws SQLException 数据库异常
* @throws E 事务中的异常类型
*/
public <E extends Exception> void commitIfTrue(
@Nonnull final ThrowingPredicate<JdbcExecutor, E> operations)
public <E extends Exception> void commitIfTrue(@Nonnull final ThrowingPredicate<JdbcExecutor, E> operations)
throws SQLException, E {
AssertTools.checkNotNull(operations, "Operations can not be null.");
try (Connection conn = this.dataSource.getConnection()) {
@@ -485,8 +469,7 @@ public class SimpleJdbcTemplate implements JdbcOperations {
@Override
public <T> T query(String sql, ResultHandler<T> resultHandler)
throws SQLException {
return JdbcOperationSupport
.query(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, resultHandler);
return JdbcOperationSupport.query(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, resultHandler);
}
// #endregion
@@ -514,12 +497,18 @@ public class SimpleJdbcTemplate implements JdbcOperations {
return JdbcOperationSupport.queryList(this.conn, sql, params, RowMapper.HASH_MAP_MAPPER);
}
/** {@inheritDoc} */
@Override
public List<DbRecord> queryRecordList(String sql, Object[] params)
throws SQLException {
return JdbcOperationSupport.queryList(this.conn, sql, params, RowMapper.RECORD_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);
return JdbcOperationSupport.queryList(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
/** {@inheritDoc} */
@@ -533,8 +522,14 @@ public class SimpleJdbcTemplate implements JdbcOperations {
@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);
return JdbcOperationSupport.queryList(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.HASH_MAP_MAPPER);
}
/** {@inheritDoc} */
@Override
public List<DbRecord> queryRecordList(String sql)
throws SQLException {
return JdbcOperationSupport.queryList(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.RECORD_MAPPER);
}
// #endregion
@@ -545,154 +540,126 @@ public class SimpleJdbcTemplate implements JdbcOperations {
@Override
public <T> Optional<T> queryFirst(String sql, Object[] params, RowMapper<T> rowMapper)
throws SQLException {
final T result = JdbcOperationSupport.queryFirst(this.conn, sql, params, rowMapper);
return Optional.ofNullable(result);
return JdbcOperationSupport.queryFirst(this.conn, sql, params, rowMapper);
}
/** {@inheritDoc} */
@Override
public <T> Optional<T> queryFirst(String sql, Object[] params, Class<T> clazz)
throws SQLException {
final T result = JdbcOperationSupport.queryFirst(this.conn, sql, params, clazz);
return Optional.ofNullable(result);
return JdbcOperationSupport.queryFirst(this.conn, sql, params, clazz);
}
/** {@inheritDoc} */
@Override
public Optional<Map<String, Object>> queryFirst(String sql, Object[] params)
throws SQLException {
final Map<String, Object> result = JdbcOperationSupport
.queryFirst(this.conn, sql, params, RowMapper.HASH_MAP_MAPPER);
return Optional.ofNullable(result);
return JdbcOperationSupport.queryFirst(this.conn, sql, params, RowMapper.HASH_MAP_MAPPER);
}
/** {@inheritDoc} */
@Override
public Optional<DbRecord> queryFirstRecord(String sql, Object[] params)
throws SQLException {
return JdbcOperationSupport.queryFirst(this.conn, sql, params, RowMapper.RECORD_MAPPER);
}
/** {@inheritDoc} */
@Override
public Optional<String> queryFirstString(String sql, Object[] params)
throws SQLException {
final String result = JdbcOperationSupport.queryFirstString(this.conn, sql, params);
return Optional.ofNullable(result);
return JdbcOperationSupport.queryFirstString(this.conn, sql, params);
}
/** {@inheritDoc} */
@Override
public OptionalInt queryFirstInt(String sql, Object[] params)
throws SQLException {
final Integer result = JdbcOperationSupport.queryFirstInt(this.conn, sql, params);
return OptionalTools.optionalOf(result);
return JdbcOperationSupport.queryFirstInt(this.conn, sql, params);
}
/** {@inheritDoc} */
@Override
public OptionalLong queryFirstLong(String sql, Object[] params)
throws SQLException {
final Long result = JdbcOperationSupport.queryFirstLong(this.conn, sql, params);
return OptionalTools.optionalOf(result);
return JdbcOperationSupport.queryFirstLong(this.conn, sql, params);
}
/** {@inheritDoc} */
@Override
public OptionalDouble queryFirstDouble(String sql, Object[] params)
throws SQLException {
final Double result = JdbcOperationSupport.queryFirstDouble(this.conn, sql, params);
return OptionalTools.optionalOf(result);
return JdbcOperationSupport.queryFirstDouble(this.conn, sql, params);
}
/** {@inheritDoc} */
@Override
public Optional<BigDecimal> queryFirstBigDecimal(String sql, Object[] params)
throws SQLException {
final BigDecimal result = JdbcOperationSupport.queryFirstBigDecimal(this.conn, sql, params);
return Optional.ofNullable(result);
return JdbcOperationSupport.queryFirstBigDecimal(this.conn, sql, params);
}
/** {@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);
return JdbcOperationSupport.queryFirst(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, rowMapper);
}
/** {@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);
return JdbcOperationSupport.queryFirst(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, clazz);
}
/** {@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);
return JdbcOperationSupport.queryFirst(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.HASH_MAP_MAPPER);
}
/** {@inheritDoc} */
@Override
public Optional<DbRecord> queryFirstRecord(String sql)
throws SQLException {
return JdbcOperationSupport.queryFirst(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY, RowMapper.RECORD_MAPPER);
}
/** {@inheritDoc} */
@Override
public Optional<String> queryFirstString(String sql)
throws SQLException {
final String result = JdbcOperationSupport
.queryFirstString(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
return Optional.ofNullable(result);
return JdbcOperationSupport.queryFirstString(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
/** {@inheritDoc} */
@Override
public OptionalInt queryFirstInt(String sql)
throws SQLException {
final Integer result = JdbcOperationSupport
.queryFirstInt(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
return OptionalTools.optionalOf(result);
return JdbcOperationSupport.queryFirstInt(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
/** {@inheritDoc} */
@Override
public OptionalLong queryFirstLong(String sql)
throws SQLException {
final Long result = JdbcOperationSupport
.queryFirstLong(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
return OptionalTools.optionalOf(result);
return JdbcOperationSupport.queryFirstLong(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
/** {@inheritDoc} */
@Override
public OptionalDouble queryFirstDouble(String sql)
throws SQLException {
final Double result = JdbcOperationSupport
.queryFirstDouble(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
return OptionalTools.optionalOf(result);
return JdbcOperationSupport.queryFirstDouble(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
/** {@inheritDoc} */
@Override
public Optional<BigDecimal> queryFirstBigDecimal(String sql)
throws SQLException {
final BigDecimal result = JdbcOperationSupport
.queryFirstBigDecimal(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
return Optional.ofNullable(result);
}
/** {@inheritDoc} */
@Override
public boolean queryAsBoolean(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 queryAsBoolean(String sql, Object[] params)
throws SQLException {
final Boolean result = JdbcOperationSupport.queryFirstBoolean(this.conn, sql, params);
return Boolean.TRUE.equals(result);
return JdbcOperationSupport.queryFirstBigDecimal(this.conn, sql, ParamBuilder.EMPTY_OBJECT_ARRAY);
}
// #endregion
@@ -736,12 +703,10 @@ public class SimpleJdbcTemplate implements JdbcOperations {
/** {@inheritDoc} */
@Override
public List<int[]> batchUpdateAndIgnoreException(String sql,
@Nullable Collection<Object[]> params,
int batchSize,
List<Exception> exceptions) throws SQLException {
return JdbcOperationSupport
.batchUpdateAndIgnoreException(this.conn, sql, params, batchSize, exceptions);
public List<int[]> batchUpdateAndIgnoreException(String sql, @Nullable Collection<Object[]> params,
int batchSize, List<Exception> exceptions)
throws SQLException {
return JdbcOperationSupport.batchUpdateAndIgnoreException(this.conn, sql, params, batchSize, exceptions);
}
// #endregion

View File

@@ -1,137 +0,0 @@
/*
* Copyright 2025 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.test;
import java.time.LocalDateTime;
import java.util.Objects;
public class AccountPO {
Long id;
String username;
String accountStatus;
LocalDateTime createTime;
Long createdBy;
LocalDateTime updateTime;
Long updatedBy;
Long version;
public AccountPO() {
}
public AccountPO(Long id, String username, String accountStatus, LocalDateTime createTime, Long createdBy,
LocalDateTime updateTime, Long updatedBy, Long version) {
this.id = id;
this.username = username;
this.accountStatus = accountStatus;
this.createTime = createTime;
this.createdBy = createdBy;
this.updateTime = updateTime;
this.updatedBy = updatedBy;
this.version = version;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAccountStatus() {
return accountStatus;
}
public void setAccountStatus(String accountStatus) {
this.accountStatus = accountStatus;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public Long getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Long createdBy) {
this.createdBy = createdBy;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
public Long getUpdatedBy() {
return updatedBy;
}
public void setUpdatedBy(Long updatedBy) {
this.updatedBy = updatedBy;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
@Override
public int hashCode() {
return Objects.hash(id, username, accountStatus, createTime, createdBy, updateTime, updatedBy, version);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AccountPO other = (AccountPO) obj;
return Objects.equals(id, other.id) && Objects.equals(username, other.username)
&& Objects.equals(accountStatus, other.accountStatus) && Objects.equals(createTime, other.createTime)
&& Objects.equals(createdBy, other.createdBy) && Objects.equals(updateTime, other.updateTime)
&& Objects.equals(updatedBy, other.updatedBy) && Objects.equals(version, other.version);
}
@Override
public String toString() {
return "AccountPO [id=" + id + ", username=" + username + ", accountStatus=" + accountStatus + ", createTime="
+ createTime + ", createdBy=" + createdBy + ", updateTime=" + updateTime + ", updatedBy=" + updatedBy
+ ", version=" + version + "]";
}
}

View File

@@ -1,47 +1,32 @@
/*
* Copyright 2023-2025 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.test;
import static org.junit.jupiter.api.Assertions.*;
import static xyz.zhouxy.jdbc.ParamBuilder.buildParams;
import static xyz.zhouxy.jdbc.ParamBuilder.*;
import static xyz.zhouxy.plusone.commons.sql.JdbcSql.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import org.h2.jdbcx.JdbcDataSource;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Resources;
import com.google.common.collect.Lists;
import xyz.zhouxy.jdbc.DbRecord;
import xyz.zhouxy.jdbc.RowMapper;
import xyz.zhouxy.jdbc.SimpleJdbcTemplate;
import xyz.zhouxy.jdbc.SimpleJdbcTemplate.JdbcExecutor;
import xyz.zhouxy.plusone.commons.sql.SQL;
import xyz.zhouxy.plusone.commons.util.IdGenerator;
import xyz.zhouxy.plusone.commons.util.IdWorker;
@@ -49,61 +34,78 @@ class SimpleJdbcTemplateTests {
private static final Logger log = LoggerFactory.getLogger(SimpleJdbcTemplateTests.class);
private static SimpleJdbcTemplate jdbcTemplate;
private static final SimpleJdbcTemplate jdbcTemplate;
@BeforeAll
static void initH2() throws IOException, SQLException {
static {
JdbcDataSource dataSource = new JdbcDataSource();
dataSource.setURL("jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=FALSE;MODE=MySQL");
dataSource.setUser("sa");
dataSource.setPassword("");
jdbcTemplate = new SimpleJdbcTemplate(dataSource);
// 建表
executeSqlFile("schema.sql");
}
@BeforeEach
void initData() throws IOException, SQLException {
// 初始化数据
executeSqlFile("data.sql");
}
static void executeSqlFile(String filePath) throws IOException, SQLException {
String[] sqls = Resources
.toString(Resources.getResource(filePath), StandardCharsets.UTF_8)
.split(";");
for (String sql : sqls) {
jdbcTemplate.update(sql);
}
@BeforeAll
static void setUp() throws SQLException {
jdbcTemplate.update("CREATE TABLE sys_account ("
+ "\n" + " id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY"
+ "\n" + " ,username VARCHAR(255) NOT NULL"
+ "\n" + " ,account_status VARCHAR(2) NOT NULL"
+ "\n" + " ,create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP"
+ "\n" + " ,created_by BIGINT NOT NULL"
+ "\n" + " ,update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP"
+ "\n" + " ,updated_by BIGINT DEFAULT NULL"
+ "\n" + " ,version BIGINT NOT NULL DEFAULT 0"
+ "\n" + ")");
jdbcTemplate.batchUpdate("INSERT INTO sys_account(id, username, account_status, created_by) VALUES (?, ?, ?, ?)", Lists.newArrayList(
buildParams(2L, "zhouxy2", "0", 108L),
buildParams(3L, "zhouxy3", "0", 108L),
buildParams(4L, "zhouxy4", "0", 108L),
buildParams(5L, "zhouxy5", "0", 108L),
buildParams(6L, "zhouxy6", "0", 108L),
buildParams(7L, "zhouxy7", "0", 108L),
buildParams(8L, "zhouxy8", "0", 108L),
buildParams(9L, "zhouxy9", "0", 108L)
), 10);
jdbcTemplate.batchUpdate("INSERT INTO sys_account(id, username, account_status, created_by, create_time, update_time, version) VALUES (?, ?, ?, ?, ?, ?, ?)", Lists.newArrayList(
buildParams(10L, "zhouxy10", "1", 118L, LocalDate.of(2000, 1, 1), LocalDate.of(2000, 1, 29), 31),
buildParams(11L, "zhouxy11", "1", 118L, LocalDate.of(2000, 1, 1), LocalDate.of(2000, 1, 29), 28),
buildParams(12L, "zhouxy12", "1", 118L, LocalDate.of(2000, 1, 1), LocalDate.of(2000, 1, 29), 25),
buildParams(13L, "zhouxy13", "1", 118L, LocalDate.of(2000, 1, 1), LocalDate.of(2000, 1, 29), 22),
buildParams(14L, "zhouxy14", "1", 118L, LocalDate.of(2000, 1, 1), LocalDate.of(2000, 1, 29), 19),
buildParams(15L, "zhouxy15", "1", 118L, LocalDate.of(2000, 1, 1), LocalDate.of(2000, 1, 29), 16),
buildParams(16L, "zhouxy16", "1", 118L, LocalDate.of(2000, 1, 1), LocalDate.of(2000, 1, 29), 13),
buildParams(17L, "zhouxy17", "1", 118L, LocalDate.of(2000, 1, 1), LocalDate.of(2000, 1, 29), 10),
buildParams(18L, "zhouxy18", "1", 118L, LocalDate.of(2000, 1, 1), LocalDate.of(2000, 1, 29), 7),
buildParams(19L, "zhouxy19", "1", 118L, LocalDate.of(2000, 1, 1), LocalDate.of(2000, 1, 29), 0)
), 10);
jdbcTemplate.update("INSERT INTO sys_account(id, username, account_status, created_by, create_time, updated_by, update_time, version) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
buildParams(20L, "zhouxy20", "2", 118L, LocalDateTime.of(2008, 8, 8, 20, 8), 31L, LocalDateTime.now(), 88L));
}
@Test
void testQuery() throws SQLException {
Object[] ids = buildParams(5, 9, 13, 14, 17, 20, 108);
String sql = "SELECT id, username, account_status FROM sys_account WHERE id IN (?, ?, ?, ?, ?, ?, ?)";
String sql = SQL.newJdbcSql()
.SELECT("id", "username", "account_status")
.FROM("sys_account")
.WHERE(IN("id", ids))
.toString();
log.info(sql);
List<Map<String, Object>> rs = jdbcTemplate.queryList(sql, ids);
for (Map<String, Object> dbRecord : rs) {
List<DbRecord> rs = jdbcTemplate.queryRecordList(sql, ids);
for (DbRecord dbRecord : rs) {
log.info("{}", dbRecord);
}
List<ImmutableMap<String, Object>> expected = ImmutableList.of(
ImmutableMap.of("id", 5L, "account_status", "0", "username", "zhouxy5"),
ImmutableMap.of("id", 9L, "account_status", "0", "username", "zhouxy9"),
ImmutableMap.of("id", 13L, "account_status", "1", "username", "zhouxy13"),
ImmutableMap.of("id", 14L, "account_status", "1", "username", "zhouxy14"),
ImmutableMap.of("id", 17L, "account_status", "1", "username", "zhouxy17"),
ImmutableMap.of("id", 20L, "account_status", "2", "username", "zhouxy20")
assertEquals(
Lists.newArrayList(
new DbRecord(ImmutableMap.of("id", 5L, "account_status", "0", "username", "zhouxy5")),
new DbRecord(ImmutableMap.of("id", 9L, "account_status", "0", "username", "zhouxy9")),
new DbRecord(ImmutableMap.of("id", 13L, "account_status", "1", "username", "zhouxy13")),
new DbRecord(ImmutableMap.of("id", 14L, "account_status", "1", "username", "zhouxy14")),
new DbRecord(ImmutableMap.of("id", 17L, "account_status", "1", "username", "zhouxy17")),
new DbRecord(ImmutableMap.of("id", 20L, "account_status", "2", "username", "zhouxy20"))
),
rs
);
assertEquals(expected, rs);
}
@Test
void testQueryExists() throws SQLException {
boolean isExists = jdbcTemplate.queryAsBoolean(
"SELECT EXISTS(SELECT 1 FROM sys_account WHERE id = ? LIMIT 1)",
buildParams(998));
assertFalse(isExists);
}
@Test
@@ -130,16 +132,16 @@ class SimpleJdbcTemplateTests {
@Test
void testUpdate() throws SQLException {
List<Map<String, Object>> keys = jdbcTemplate.update(
List<DbRecord> keys = jdbcTemplate.update(
"UPDATE sys_account SET account_status = ?, version = version + 1, update_time = now(), updated_by = ? WHERE id = ? AND version = ?",
buildParams("7", 886L, 20L, 88L),
RowMapper.HASH_MAP_MAPPER);
RowMapper.RECORD_MAPPER);
assertEquals(1, keys.size());
log.info("keys: {}", keys);
keys = jdbcTemplate.update(
"UPDATE sys_account SET account_status = ?, version = version + 1, update_time = now(), updated_by = ? WHERE id = ? AND version = ?",
buildParams("-1", 886L, 20L, 88L),
RowMapper.HASH_MAP_MAPPER);
RowMapper.RECORD_MAPPER);
assertEquals(0, keys.size());
}
@@ -163,7 +165,7 @@ class SimpleJdbcTemplateTests {
Optional<Map<String, Object>> first = jdbcTemplate
.queryFirst("SELECT * FROM sys_account WHERE id = ?", buildParams(id));
log.info("first: {}", first);
assertFalse(first.isPresent());
assertTrue(!first.isPresent());
}
// 没有异常,提交事务
@@ -196,7 +198,7 @@ class SimpleJdbcTemplateTests {
Optional<Map<String, Object>> first = jdbcTemplate
.queryFirst("SELECT * FROM sys_account WHERE id = ?", buildParams(id));
log.info("first: {}", first);
assertFalse(first.isPresent());
assertTrue(!first.isPresent());
}
// 返回 false回滚
@@ -211,7 +213,7 @@ class SimpleJdbcTemplateTests {
Optional<Map<String, Object>> first = jdbcTemplate
.queryFirst("SELECT * FROM sys_account WHERE id = ?", buildParams(id));
log.info("first: {}", first);
assertFalse(first.isPresent());
assertTrue(!first.isPresent());
}
// 返回 true提交事务
@@ -244,3 +246,120 @@ class SimpleJdbcTemplateTests {
log.info("{}", t);
}
}
class AccountPO {
Long id;
String username;
String accountStatus;
LocalDateTime createTime;
Long createdBy;
LocalDateTime updateTime;
Long updatedBy;
Long version;
public AccountPO() {
}
public AccountPO(Long id, String username, String accountStatus, LocalDateTime createTime, Long createdBy,
LocalDateTime updateTime, Long updatedBy, Long version) {
this.id = id;
this.username = username;
this.accountStatus = accountStatus;
this.createTime = createTime;
this.createdBy = createdBy;
this.updateTime = updateTime;
this.updatedBy = updatedBy;
this.version = version;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAccountStatus() {
return accountStatus;
}
public void setAccountStatus(String accountStatus) {
this.accountStatus = accountStatus;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public Long getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Long createdBy) {
this.createdBy = createdBy;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
public Long getUpdatedBy() {
return updatedBy;
}
public void setUpdatedBy(Long updatedBy) {
this.updatedBy = updatedBy;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
@Override
public int hashCode() {
return Objects.hash(id, username, accountStatus, createTime, createdBy, updateTime, updatedBy, version);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AccountPO other = (AccountPO) obj;
return Objects.equals(id, other.id) && Objects.equals(username, other.username)
&& Objects.equals(accountStatus, other.accountStatus) && Objects.equals(createTime, other.createTime)
&& Objects.equals(createdBy, other.createdBy) && Objects.equals(updateTime, other.updateTime)
&& Objects.equals(updatedBy, other.updatedBy) && Objects.equals(version, other.version);
}
@Override
public String toString() {
return "AccountPO [id=" + id + ", username=" + username + ", accountStatus=" + accountStatus + ", createTime="
+ createTime + ", createdBy=" + createdBy + ", updateTime=" + updateTime + ", updatedBy=" + updatedBy
+ ", version=" + version + "]";
}
}

View File

@@ -1,23 +0,0 @@
truncate table sys_account;
INSERT INTO sys_account(id, username, account_status, created_by) VALUES (2, 'zhouxy2', '0', 108);
INSERT INTO sys_account(id, username, account_status, created_by) VALUES (3, 'zhouxy3', '0', 108);
INSERT INTO sys_account(id, username, account_status, created_by) VALUES (4, 'zhouxy4', '0', 108);
INSERT INTO sys_account(id, username, account_status, created_by) VALUES (5, 'zhouxy5', '0', 108);
INSERT INTO sys_account(id, username, account_status, created_by) VALUES (6, 'zhouxy6', '0', 108);
INSERT INTO sys_account(id, username, account_status, created_by) VALUES (7, 'zhouxy7', '0', 108);
INSERT INTO sys_account(id, username, account_status, created_by) VALUES (8, 'zhouxy8', '0', 108);
INSERT INTO sys_account(id, username, account_status, created_by) VALUES (9, 'zhouxy9', '0', 108);
INSERT INTO sys_account(id, username, account_status, created_by, create_time, update_time, `version`) VALUES (10, 'zhouxy10', '1', 118, '2000-01-01', '2000-01-29', 31);
INSERT INTO sys_account(id, username, account_status, created_by, create_time, update_time, `version`) VALUES (11, 'zhouxy11', '1', 118, '2000-01-01', '2000-01-29', 28);
INSERT INTO sys_account(id, username, account_status, created_by, create_time, update_time, `version`) VALUES (12, 'zhouxy12', '1', 118, '2000-01-01', '2000-01-29', 25);
INSERT INTO sys_account(id, username, account_status, created_by, create_time, update_time, `version`) VALUES (13, 'zhouxy13', '1', 118, '2000-01-01', '2000-01-29', 22);
INSERT INTO sys_account(id, username, account_status, created_by, create_time, update_time, `version`) VALUES (14, 'zhouxy14', '1', 118, '2000-01-01', '2000-01-29', 19);
INSERT INTO sys_account(id, username, account_status, created_by, create_time, update_time, `version`) VALUES (15, 'zhouxy15', '1', 118, '2000-01-01', '2000-01-29', 16);
INSERT INTO sys_account(id, username, account_status, created_by, create_time, update_time, `version`) VALUES (16, 'zhouxy16', '1', 118, '2000-01-01', '2000-01-29', 13);
INSERT INTO sys_account(id, username, account_status, created_by, create_time, update_time, `version`) VALUES (17, 'zhouxy17', '1', 118, '2000-01-01', '2000-01-29', 10);
INSERT INTO sys_account(id, username, account_status, created_by, create_time, update_time, `version`) VALUES (18, 'zhouxy18', '1', 118, '2000-01-01', '2000-01-29', 7 );
INSERT INTO sys_account(id, username, account_status, created_by, create_time, update_time, `version`) VALUES (19, 'zhouxy19', '1', 118, '2000-01-01', '2000-01-29', 0 );
INSERT INTO sys_account(id, username, account_status, created_by, create_time, updated_by, update_time, version) VALUES (20, 'zhouxy20', '2', 118, '2008-08-08 20:08:00', 31, now(), 88);

View File

@@ -1,10 +0,0 @@
CREATE TABLE sys_account (
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
, `username` VARCHAR(255) NOT NULL
, `account_status` VARCHAR(2) NOT NULL
, `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
, `created_by` BIGINT NOT NULL
, `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
, `updated_by` BIGINT DEFAULT NULL
, `version` BIGINT NOT NULL DEFAULT 0
)