【问题标题】:Hibernate / JPA2 Duplicate Records休眠/JPA2 重复记录
【发布时间】:2016-01-20 01:45:13
【问题描述】:

我正在尝试为一个项目学习 JPA 2 的基础知识,使用 Hibernate。我不确定的一件事是如何正确执行复合键。出于某种原因,当我简单地打印出表格的值时,我得到了两次。

表格本身是:

表格:Anim_Type

CrashNumber RecordNumber AnimalType
1000        1            2
1000        1            10

在我的主课中,我在它(Crash)和 AnimalTypes 之间有一个@OneToMany 关系:

@OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
@JoinColumn(name = "CRASH_NUMBER")
public List<AnimalType> getAnimalTypes() {
    return animalTypes;
}

AnimalType @Entity 应该具有所有 3 列的主键。这是 AnimalType 类:

@Entity
@Table(name = "ANIM_TYPE")
public class AnimalType {

private AnimalTypePK pk;

@EmbeddedId
@AttributeOverrides( {
    @AttributeOverride(name = "crashNum", column = @Column(name = "CRASH_NUMBER")),
    @AttributeOverride(name = "recordNum", column = @Column(name = "RECORD_NUMBER")),
    @AttributeOverride(name = "animalType", column = @Column(name = "ANIMAL_TYPE"))
})
public AnimalTypePK getPk() {
    return pk;
}

public void setPk(AnimalTypePK pk) {
    this.pk = pk;
}

public void print() {
    System.out.println("AnimalType: " + pk.getCrashNum() + " " + pk.getRecordNum() + " " + pk.getAnimalType());
}


}

我的 AnimalTypePK 类是:

@Embeddable
public class AnimalTypePK implements Serializable {

private static final long serialVersionUID = 1L;
private int crashNum;
private int recordNum;
private int animalType;

// getters and setters, plus hashCode() and equals(Object).
// no other JPA annotations in this class

}

当我使用上面的代码时,一切正常,但是当我打印 AnimalTypes 时,表中的 2 行重复:

动物种类

AnimalType: 1000 1 10
AnimalType: 1000 1 2
AnimalType: 1000 1 10
AnimalType: 1000 1 2

我不明白为什么?

谁能帮忙?

其次,我使用 AnimalType 中的 @AttributeOverrides 注解来告诉 Hibernate 列名。这是正确的方法吗?

谢谢!

克里斯

编辑: 我之前确实看到了标记的帖子,并按照接受的答案的方法,并将@Column 放入AnimalTypePK(取出AnimalType 中的@AttributeOverrides)。 但是当我尝试它时,我得到了一个例外:

Exception in thread "main"      org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:242)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:225)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:417)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:131)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
at com.sun.proxy.$Proxy34.findOne(Unknown Source)
at com.dbprototype.services.CrashService.readCrash(CrashService.java:28)
at com.dbprototype.services.CrashService$$FastClassBySpringCGLIB$$473ea387.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:718)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:654)
at com.dbprototype.services.CrashService$$EnhancerBySpringCGLIB$$a311f3d6.readCrash(<generated>)
at com.dbprototype.main.DBTest.main(DBTest.java:20)
Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:63)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:79)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.getResultSet(AbstractLoadPlanBasedLoader.java:434)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:186)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:121)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86)
at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:167)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3955)
at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:508)
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:478)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:219)
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:278)
at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:121)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:89)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1129)
at org.hibernate.internal.SessionImpl.access$2600(SessionImpl.java:164)
at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2696)
at org.hibernate.internal.SessionImpl.get(SessionImpl.java:975)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:1075)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:1039)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:293)
at com.sun.proxy.$Proxy29.find(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findOne(SimpleJpaRepository.java:235)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:483)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:468)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:440)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
... 19 more
Caused by: java.sql.SQLSyntaxErrorException: ORA-00904: "ANIMALTYPE1_"."RECORDNUM": invalid identifier

at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:450)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:399)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1017)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:655)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:249)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:566)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:215)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:58)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:776)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:897)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1034)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3820)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3867)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1502)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:70)
... 59 more

【问题讨论】:

  • 不确定您实际从哪里打印它们。但是放置复合键的列名的正确方法是在AnimalTypePK 类中使用通常的@Column 注释。
  • @jbx 请参阅上面的我的编辑 cmets。我确实看到了那个帖子,基本上它没有工作。获取异常。
  • 你确定表中的列名和你说的一样吗?当您的列应该是RECORD_NUMBER 时,为什么引用RECORDNUM 的异常?您能否正确更新完整代码并将异常的全部详细信息以及您在 Oracle 数据库中的表结构放入其中?有些东西似乎不匹配。
  • 是的,列名是正确的。我在这里缩写了它们,但检查了我的代码,并且列匹配。我一直假设异常是指 RECORDNUM,因为这是该列的 Java 变量名,因此 Java 变量名和数据库列之间存在某种映射问题。

标签: java hibernate jpa


【解决方案1】:

该问题与您在协会中使用 EAGER 的事实无关。

您可以在此处找到进一步的讨论。

https://howtoprogramwithjava.com/how-to-fix-duplicate-data-from-hibernate-queries/

Hibernate Criteria returns children multiple times with FetchType.EAGER

然后可能的修复是删除 Eager Fetch 或使用 Set 而不是 List 映射此关联。

关于您关于为什么使用 SET 已修复它的后续问题....

好吧,如果我们考虑以下几点:

持久化上下文的主要作用是确保一个 数据库实体对象由不超过一个内存中表示 同一 EntityManager 中的实体对象。每个 EntityManager 管理自己的持久性上下文。因此,数据库对象可以 由不同的内存实体对象表示 EntityManager 实例。 但检索相同的数据库对象更多 不止一次使用相同的 EntityManager 应该总是导致 相同的内存中实体对象。

http://www.objectdb.com/java/jpa/persistence/managed

鉴于上述陈述,如果我们考虑您原来的重复列表:

  • 动物类型:1000 1 10
  • 动物类型:1000 1 2
  • 动物类型:1000 1 10
  • 动物类型:1000 1 2

我们期望(假设 AnimalType 具有默认的 equals 方法或正确实现的自定义 equals 方法)

list.get(0).equals(list.get(2)) == true 

list.get(1).equals(list.get(3)) == true

当然,由于 Set 不能包含重复项,因此作为使用 Set 的副作用,重复记录会被过滤掉。

https://docs.oracle.com/javase/7/docs/api/java/util/Set.html

不包含重复元素的集合。更正式地说,集合 不包含元素对 e1 和 e2 使得 e1.equals(e2)...

【讨论】:

  • 谢谢艾伦!我最初使用延迟加载,但这总是给我:线程“主”org.hibernate.LazyInitializationException中的异常:未能延迟初始化角色集合:com.dbprototype.domain.Crash.animalTypes,无法初始化代理 - 否会议。不知道为什么。我刚刚尝试使用 Set 和 List 进行延迟加载,给出了相同的异常。除了改成懒加载,代码都是一样的。
  • 懒加载问题完全是另一个问题。您应该接受这个关于重复的原始问题的答案,并进一步研究延迟加载,因为如果使用 JPA,这是您真正必须了解的内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-11
相关资源
最近更新 更多