我正在使用一个使用JPA(Hibernate)作为持久层的Spring Boot应用程序。
我目前正在实施迁移功能。我们基本上将系统的所有现有实体转储到XML文件中。此导出也包括实体的ID。
我遇到的问题位于另一边,重新导入现有数据。在此步骤中,XML再次转换为Java对象并持久保存到数据库中。
尝试保存实体时,我使用merge
类的EntityManager
方法,该方法有效:一切都已成功保存。
然而,当我打开Hibernate的查询日志记录时,我看到在每个插入查询之前,执行一个select查询以查看具有该id的实体是否已经存在。这是因为实体已经拥有我提供的ID。
我理解这种行为,它实际上是有道理的。但我确信这些ID不会存在,因此选择对我的情况没有意义。我节省了数千条记录,这意味着对大型表格进行了数千次选择查询,这大大减慢了导入过程。
我的问题:有没有办法在插入"之前检查实体是否存在?关闭?
其他信息:
当我使用entityManager.persist()
而不是合并时,我得到了这个例外:
org.hibernate.PersistentObjectException:传递给的分离实体 坚持
为了能够使用提供的/提供的id,我使用这个id生成器:
@Id
@GeneratedValue(generator = "use-id-or-generate")
@GenericGenerator(name = "use-id-or-generate", strategy = "be.stackoverflowexample.core.domain.UseIdOrGenerate")
@JsonIgnore
private String id;
发电机本身:
public class UseIdOrGenerate extends UUIDGenerator {
private String entityName;
@Override
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
entityName = params.getProperty(ENTITY_NAME);
super.configure(type, params, serviceRegistry);
}
@Override
public Serializable generate(SessionImplementor session, Object object)
{
Serializable id = session
.getEntityPersister(entityName, object)
.getIdentifier(object, session);
if (id == null) {
return super.generate(session, object);
} else {
return id;
}
}
}
答案 0 :(得分:2)
如果您确定永远不会更新数据库中的任何现有条目,并且所有实体都应该总是刚刚插入,那么我会选择<%= debug @article %>
操作而不是persist
。
每次更新
在这种情况下(id字段被设置为自动生成),唯一的方法是从id字段中删除生成注释并将配置保留为:
merge
所以基本上设置id以便始终手动分配。然后,即使id存在,持久性提供程序也会将您的实体视为瞬态。这意味着@Id
@JsonIgnore
private String id;
将起作用,并且不会生成额外的选择。
答案 1 :(得分:1)
我不确定我是否填写了身份证。如果您在应用程序端填写它,请检查answer here。我在下面复制了它:
以下是使用Spring Data存储库时使用的Spring SimpleJpaRepository的代码:
@Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
它执行以下操作:
默认情况下,Spring Data JPA会检查给定实体的identifier属性。如果identifier属性为null,则该实体将被假定为new,否则将被假定为new。
Link to Spring Data documentation
因此,如果你的某个实体的ID字段不为null,那么Spring将使Hibernate进行更新(之前是SELECT)。
您可以通过同一文档中列出的两种方式覆盖此行为。一种简单的方法是让你的实体实现Persistable(而不是Serializable),这将使你实现方法“isNew”。