什么是 SQL/JDBC 等同于 JPA merge API?它到底做了什么?
What is the SQL/JDBC equivalent to JPA merge API? What does it exactly do?
我正在使用 JDBC 将 JPA api 之类的持久化、保存、合并、刷新、分离和删除迁移到普通 SQL,我发现它很难理解EntityManager.merge(someTask).
的概念
我试了一个SQLupdate合并的查询API但是合并的解释如下合并的状态将给定的实体放入当前持久性上下文。但是对于普通的 SQL 和 JDBC 很难理解如何做同样的事情,我也需要处理 OptimisticLock。
用于JPA的实体class如下。
@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(任务)相当于 SQL/HSQL。
Merge in essence is the process of merging an existing record in a table with what has been provided in the statement (i.e. UPDATE if the record exists else INSERT). Also known as UPSERT
.
假设您有一个 table tbl_person,它具有主键 person_ssn 和另外两列,即姓名和年龄。如果您想在恰好存在的 person_ssn 上插入语句,DB 将抛出错误。如果 person_ssn 不存在,您的要求是插入一条记录,否则更新姓名和年龄。在这种情况下,您将使用 Merge。
实现这个的方法很少,其中两个是
- 至少发出两个 DML 语句。首先在 person_ssn 上执行 SELECT 并根据是否找到记录,随后,您将发出 UPDATE 或 INSERT 语句
- 使用MERGE SQL语句。这是更现代和直接的方式,但并非所有数据库都支持它。阅读更多信息 here. Further, just to get an idea, check here,了解 MERGE SQL 语句如何在支持它的 SQL 服务器中工作
就 Java JPA 而言,实现抽象了这个概念。根据数据库对 MERGE SQL 语句的支持,要么使用它,要么发出两个语句(SELECT 后跟 UPDATE 或 INSERT)来完成相同的操作。
hsqldb 根据提供的评论提供 MERGE SQL 支持。
除了 upsert
之外,还有更多语义合并(在 ORM 上下文的情况下)。本质上,您的实体模型是使用内存指针相互关联的对象图。 merge API 的 objective 是为了能够用当前状态反映对象图的预期未来状态。通常 ORM 会发出 SQL insert/updates/deletes 来反映预期的未来状态,而不一定是 SQL MERGE。例如,未来的实体状态有一个一对多的关系为 null - 这将导致 ORM 发出查询以取消子 table 中的外键以反映此状态。简而言之 - 当您将一个对象(它是一个互连对象的图)传递给 merge 时,ORM 首先为各个对象确定它们是否需要新持久化或者它们是否包含已经持久化数据的标识符然后将它们加载到持久化上下文中(如果还没有)并应用所有数据更改和关系更新。最后,ORM 的脏检查机制确保生成等效的 SQL 来反映这个最终状态。
EntityManager - merge(T entity) Merge the state of the given entity into the
current persistence context.
我正在使用 JDBC 将 JPA api 之类的持久化、保存、合并、刷新、分离和删除迁移到普通 SQL,我发现它很难理解EntityManager.merge(someTask).
的概念我试了一个SQLupdate合并的查询API但是合并的解释如下合并的状态将给定的实体放入当前持久性上下文。但是对于普通的 SQL 和 JDBC 很难理解如何做同样的事情,我也需要处理 OptimisticLock。
用于JPA的实体class如下。
@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(任务)相当于 SQL/HSQL。
Merge in essence is the process of merging an existing record in a table with what has been provided in the statement (i.e. UPDATE if the record exists else INSERT). Also known as UPSERT
.
假设您有一个 table tbl_person,它具有主键 person_ssn 和另外两列,即姓名和年龄。如果您想在恰好存在的 person_ssn 上插入语句,DB 将抛出错误。如果 person_ssn 不存在,您的要求是插入一条记录,否则更新姓名和年龄。在这种情况下,您将使用 Merge。
实现这个的方法很少,其中两个是
- 至少发出两个 DML 语句。首先在 person_ssn 上执行 SELECT 并根据是否找到记录,随后,您将发出 UPDATE 或 INSERT 语句
- 使用MERGE SQL语句。这是更现代和直接的方式,但并非所有数据库都支持它。阅读更多信息 here. Further, just to get an idea, check here,了解 MERGE SQL 语句如何在支持它的 SQL 服务器中工作
就 Java JPA 而言,实现抽象了这个概念。根据数据库对 MERGE SQL 语句的支持,要么使用它,要么发出两个语句(SELECT 后跟 UPDATE 或 INSERT)来完成相同的操作。
hsqldb 根据提供的评论提供 MERGE SQL 支持。
除了 upsert
之外,还有更多语义合并(在 ORM 上下文的情况下)。本质上,您的实体模型是使用内存指针相互关联的对象图。 merge API 的 objective 是为了能够用当前状态反映对象图的预期未来状态。通常 ORM 会发出 SQL insert/updates/deletes 来反映预期的未来状态,而不一定是 SQL MERGE。例如,未来的实体状态有一个一对多的关系为 null - 这将导致 ORM 发出查询以取消子 table 中的外键以反映此状态。简而言之 - 当您将一个对象(它是一个互连对象的图)传递给 merge 时,ORM 首先为各个对象确定它们是否需要新持久化或者它们是否包含已经持久化数据的标识符然后将它们加载到持久化上下文中(如果还没有)并应用所有数据更改和关系更新。最后,ORM 的脏检查机制确保生成等效的 SQL 来反映这个最终状态。
EntityManager - merge(T entity) Merge the state of the given entity into the current persistence context.