Hibernate / JPA2重复记录

时间:2016-01-20 01:45:13

标签: java hibernate jpa

我正在尝试使用Hibernate学习JPA 2的基础知识。我不确定的一件事是如何正确地进行复合键。出于某种原因,当我简单地打印出我的桌子的值时,我会得到它们两次。

表格本身是:

表: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

1 个答案:

答案 0 :(得分:0)

该问题与您在关联中使用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修复它的后续问题....

好吧,如果我们考虑以下内容:

  

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

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

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

  • AnimalType:1000 1 10
  • AnimalType:1000 1 2
  • AnimalType:1000 1 10
  • AnimalType: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)......