【问题标题】:What is the SQL/JDBC equivalent to JPA merge API? What does it exactly do?与 JPA 合并 API 等效的 SQL/JDBC 是什么?它究竟是做什么的?
【发布时间】:2019-12-18 17:10:03
【问题描述】:

我正在使用 JDBC 将 JPA api (如持久、保存、合并、刷新、分离和删除)迁移到普通 SQL,我发现很难理解 EntityManager.merge(someTask) 的概念。

我尝试了对合并 API 的 SQL update 查询,但合并的解释如下 将给定实体的状态合并到当前持久性上下文中。但是使用普通的 SQL 和 JDBC 很难理解如何做同样的事情,我也需要处理 OptimisticLock。

用于JPA的实体类如下。

@Entity
@Table(name = "TASK", indexes = {@Index(name = "RIO", columnList = "priority", unique = false),
@Index(name = "EXP", columnList = "expiry", unique = false), 
@Index(name = "STA", columnList = "taskStatus", unique = false),
@Index(name = "CAT", columnList = "category", unique = false),
@Index(name = "NEXTTRY", columnList = "nextTry", unique = false)})

public class TaskEntity {

@Version
private int version;

@Basic
@Column(length = Integer.MAX_VALUE, columnDefinition = "varchar(" + Integer.MAX_VALUE + ")")
private String taskId;

@Basic
private String category;

@ElementCollection(fetch = FetchType.EAGER)
@MapKeyColumn(name = "KEY")
@CollectionTable(name = "TASKPROPERTIES", foreignKey = @ForeignKey(
                 name = "TASK_ID_FK",
                 foreignKeyDefinition = "FOREIGN KEY (TASKENTITY_ID) REFERENCES TASK (ID) ON DELETE CASCADE"))

@Column(length = Integer.MAX_VALUE, columnDefinition = "varchar(" + Integer.MAX_VALUE + ")")
private Map<String, String> TaskProperties;

@Basic
@Column(length = Integer.MAX_VALUE, columnDefinition = "varchar(" + Integer.MAX_VALUE + ")")
private String destination;

@Enumerated(EnumType.STRING)
private TaskStatus taskStatus;

@Basic
private String type;

@Basic
private Long expiry;

@Basic
private Long nextTry;

@Basic
private Integer retries;

@Basic
private Integer priority;

//Setters and Getters
//Equals and HashCode

}

因此,EntityManger.merge(task) 相当于 SQL/HSQL。

【问题讨论】:

  • JPA 的 merge 是一个在没有实体管理器和分离实体的情况下不存在的概念。
  • 任何有关合并的 SQL 等价物的信息都会很棒:-)

标签: java sql jpa jdbc hsqldb


【解决方案1】:

Merge 本质上是将表中现有记录与语句中提供的记录合并的过程(即 UPDATE 如果记录存在 else INSERT )。也称为UPSERT

假设您有一个表 tbl_person,它具有主键 person_ssn 和另外两个列,即名称和年龄。如果您想在恰好存在的 person_ssn 上插入语句,DB 将抛出错误。如果 person_ssn 不存在,您的要求是插入一条记录,否则更新姓名和年龄。在这种情况下,您将使用 Merge

实现这一点的方法很少,其中两种是

  1. 至少发出两条 DML 语句。首先对 person_ssn 执行 SELECT 并根据您是否找到记录,随后,您将发出 UPDATEINSERT 语句
  2. 使用 MERGE SQL 语句。这是更现代和更直接的方式,但并非所有数据库都支持它。阅读更多信息here。此外,只是想了解一下,请查看here,了解 MERGE SQL 语句在支持它的 SQL Server 中是如何工作的

就 Java JPA 而言,实现抽象了这个概念。根据 DB 对 MERGE SQL 语句的支持,要么使用它,要么发出两条语句(SELECT 后跟 UPDATE 或 INSERT)来完成相同的操作。

hsqldb 根据提供的评论提供 MERGE SQL 支持。

【讨论】:

【解决方案2】:

除了upsert 之外,还有更多的语义需要合并(在 ORM 上下文的情况下)。本质上,您的实体模型是使用内存指针相互关联的对象图。合并 API 的目标是能够用当前状态反映对象图的预期未来状态。通常,ORM 会发出 SQL 插入/更新/删除以反映预期的未来状态,而不一定是 SQL MERGE。例如,未来实体状态的一对多关系为 null - 这将导致 ORM 发出查询以使子表中的外键无效以反映此状态。简而言之 - 当您将一个对象(这是一个互连对象的图)传递给 merge 时,ORM 首先确定各个对象是否需要新持久化,或者它们是否包含已持久化数据的标识符,然后将它们加载到持久化上下文中(如果还没有)并应用所有数据更改和关系更新。最后,ORM 的脏检查机制确保生成等效的 SQL 来反映这个最终状态。

EntityManager - merge(T entity) 将给定实体的状态合并到 当前的持久化上下文。

【讨论】:

    猜你喜欢
    • 2019-12-20
    • 1970-01-01
    • 1970-01-01
    • 2013-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多