diff --git a/CHANGELOG.md b/CHANGELOG.md
index 11ddb22fb..0fef330cd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,7 +10,8 @@
* 【core 】 增加KetamaHash(issue#2084@Github)
* 【crypto 】 增加SignUtil
* 【json 】 JSONGetter增加getBeanList方法
-* 【core 】 ObjectUtil 添加三个defaultIfXxxx方法,用于节省CPU及内存损耗。(pr#2094@Github)
+* 【core 】 ObjectUtil 添加三个defaultIfXxxx方法,用于节省CPU及内存损耗(pr#2094@Github)
+* 【db 】 增加单条数据原生upsert语义支持(pr#501@Gitee)
*
### 🐞Bug修复
* 【core 】 修复setter重载导致匹配错误(issue#2082@Github)
diff --git a/hutool-db/src/main/java/cn/hutool/db/DialectRunner.java b/hutool-db/src/main/java/cn/hutool/db/DialectRunner.java
index b1003b987..26e18bc09 100644
--- a/hutool-db/src/main/java/cn/hutool/db/DialectRunner.java
+++ b/hutool-db/src/main/java/cn/hutool/db/DialectRunner.java
@@ -96,6 +96,7 @@ public class DialectRunner implements Serializable {
* @param keys 需要检查唯一性的字段
* @return 插入行数
* @throws SQLException SQL执行异常
+ * @since 5.7.20
*/
public int upsert(Connection conn, Entity record, String... keys) throws SQLException {
PreparedStatement ps = getDialect().psForUpsert(conn, record, keys);
@@ -106,12 +107,26 @@ public class DialectRunner implements Serializable {
DbUtil.close(ps);
}
} else {
- final Entity where = record.filter(keys);
- if (MapUtil.isNotEmpty(where) && count(conn, where) > 0) {
- return update(conn, record, where);
- } else {
- return insert(conn, record).length;
- }
+ return insertOrUpdate(conn, record, keys);
+ }
+ }
+
+ /**
+ * 插入或更新数据
+ * 此方法不会关闭Connection
+ *
+ * @param conn 数据库连接
+ * @param record 记录
+ * @param keys 需要检查唯一性的字段
+ * @return 插入行数
+ * @throws SQLException SQL执行异常
+ */
+ public int insertOrUpdate(Connection conn, Entity record, String... keys) throws SQLException {
+ final Entity where = record.filter(keys);
+ if (MapUtil.isNotEmpty(where) && count(conn, where) > 0) {
+ return update(conn, record, where);
+ } else {
+ return insert(conn, record)[0];
}
}
diff --git a/hutool-db/src/main/java/cn/hutool/db/SqlConnRunner.java b/hutool-db/src/main/java/cn/hutool/db/SqlConnRunner.java
index 95290d6db..28f1bfc2b 100644
--- a/hutool-db/src/main/java/cn/hutool/db/SqlConnRunner.java
+++ b/hutool-db/src/main/java/cn/hutool/db/SqlConnRunner.java
@@ -1,7 +1,6 @@
package cn.hutool.db;
import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.map.MapUtil;
import cn.hutool.db.dialect.Dialect;
import cn.hutool.db.dialect.DialectFactory;
import cn.hutool.db.handler.EntityListHandler;
@@ -15,7 +14,6 @@ import cn.hutool.db.sql.SqlUtil;
import javax.sql.DataSource;
import java.sql.Connection;
-import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
@@ -23,7 +21,8 @@ import java.util.List;
/**
* SQL执行类
* 此执行类只接受方言参数,不需要数据源,只有在执行方法时需要数据库连接对象
- * 此对象存在的意义在于,可以由使用者自定义数据库连接对象,并执行多个方法,方便事务的统一控制或减少连接对象的创建关闭
+ * 此对象存在的意义在于,可以由使用者自定义数据库连接对象,并执行多个方法,方便事务的统一控制或减少连接对象的创建关闭
+ * 相比{@link DialectRunner},此类中提供了更多重载方法
*
* @author Luxiaolei
*/
@@ -83,25 +82,6 @@ public class SqlConnRunner extends DialectRunner {
//---------------------------------------------------------------------------- CRUD start
- /**
- * 插入或更新数据
- * 此方法不会关闭Connection
- *
- * @param conn 数据库连接
- * @param record 记录
- * @param keys 需要检查唯一性的字段
- * @return 插入行数
- * @throws SQLException SQL执行异常
- */
- public int insertOrUpdate(Connection conn, Entity record, String... keys) throws SQLException {
- final Entity where = record.filter(keys);
- if (MapUtil.isNotEmpty(where) && count(conn, where) > 0) {
- return update(conn, record, where);
- } else {
- return insert(conn, record);
- }
- }
-
/**
* 批量插入数据
* 需要注意的是,批量插入每一条数据结构必须一致。批量插入数据时会获取第一条数据的字段结构,之后的数据会按照这个格式插入。
diff --git a/hutool-db/src/main/java/cn/hutool/db/dialect/Dialect.java b/hutool-db/src/main/java/cn/hutool/db/dialect/Dialect.java
index 16058bc4c..d37a7e867 100644
--- a/hutool-db/src/main/java/cn/hutool/db/dialect/Dialect.java
+++ b/hutool-db/src/main/java/cn/hutool/db/dialect/Dialect.java
@@ -144,13 +144,15 @@ public interface Dialect extends Serializable {
}
/**
- * 构建用于upsert的PreparedStatement
+ * 构建用于upsert的PreparedStatement
+ * 方言实现需实现此默认方法,默认返回{@code null}
*
* @param conn 数据库连接对象
* @param entity 数据实体类(包含表名)
* @param keys 查找字段
* @return PreparedStatement
* @throws SQLException SQL执行异常
+ * @since 5.7.20
*/
default PreparedStatement psForUpsert(Connection conn, Entity entity, String... keys) throws SQLException {
return null;
diff --git a/hutool-db/src/main/java/cn/hutool/db/sql/SqlBuilder.java b/hutool-db/src/main/java/cn/hutool/db/sql/SqlBuilder.java
index ac666054b..fcf09c671 100644
--- a/hutool-db/src/main/java/cn/hutool/db/sql/SqlBuilder.java
+++ b/hutool-db/src/main/java/cn/hutool/db/sql/SqlBuilder.java
@@ -310,7 +310,6 @@ public class SqlBuilder implements Builder {
if (null != wrapper) {
// 包装表名
- // entity = wrapper.wrap(entity);
entity.setTableName(wrapper.wrap(entity.getTableName()));
}
diff --git a/hutool-db/src/main/java/cn/hutool/db/sql/Wrapper.java b/hutool-db/src/main/java/cn/hutool/db/sql/Wrapper.java
index fd823804e..12ee7778d 100644
--- a/hutool-db/src/main/java/cn/hutool/db/sql/Wrapper.java
+++ b/hutool-db/src/main/java/cn/hutool/db/sql/Wrapper.java
@@ -7,6 +7,7 @@ import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Entity;
+import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map.Entry;
@@ -17,7 +18,8 @@ import java.util.Map.Entry;
* @author Looly
*
*/
-public class Wrapper {
+public class Wrapper implements Serializable {
+ private static final long serialVersionUID = 1L;
/** 前置包装符号 */
private Character preWrapQuote;