【问题标题】:Do i have a Hibernate cache or mapping error?我有 Hibernate 缓存或映射错误吗?
【发布时间】:2013-04-06 23:15:52
【问题描述】:

我正在使用以下框架:

  • 休眠 4.2.0.Final
  • Spring 3.2.2.RELEASE
  • Spring Data Jpa 1.1.0.RELEASE
  • HSQL 2.2.9
  • TestNG 6.1.1

我有 2 个实体:

实体 A:

@Entity
@Table( name = "A" )
public class A {

    @Id
    @GeneratedValue( strategy = GenerationType.IDENTITY )
    private Long id;

    @OneToMany( fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "a" )
    private Set<B> b = new HashSet<B>();

    //... getter and setter

}

和实体 B:

@Entity
@Table( name = "B" )
public class B {

    @Id
    @GeneratedValue( strategy = GenerationType.IDENTITY )
    private Long id;

    @ManyToOne
    @JoinColumn( name = "a_id" )
    private A a;

    //... getter and setter

}

我为他们制作了 Spring Data JPARepositories:

@Repository
public interface ARepository
        extends JpaRepository<A, Long> {

}

@Repository
public interface BRepository
        extends JpaRepository<B, Long> {

}

然后我写了一个测试看看映射是否有效:

@TransactionConfiguration( defaultRollback = true )
@ContextConfiguration
public class ARepositoryTest
        extends AbstractTransactionalTestNGSpringContextTests {

    @Inject
    @Setter
    private ARepository aRepository;

    @Inject
    @Setter
    private BRepository bRepository;


    @Test( groups = { "integration" } )
    public void testSaveWithFeed() {

        A a = new A();
        aRepository.saveAndFlush( a );

        B b = new B();
        b.setA( a );
        bRepository.saveAndFlush( b );

        A findOne = aRepository.findOne( a.getId() );
        Assert.assertEquals( 1, findOne.getB().size() );

    }
}

但测试失败:

Hibernate: insert into A (id) values (default)
Hibernate: insert into B (id, a_id) values (default, ?)
FAILED: testSaveWithA
java.lang.AssertionError: expected [1] but found [0]

我不明白为什么。映射中是否缺少某些内容,或者我是否必须清除休眠缓存? 我看到没有新的选择查询,所以休眠正在缓存 A 对象 - 但它不应该更新从 A 到缓存中 B 的引用吗??

作为附加信息,这里是我的 persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    xmlns="http://java.sun.com/xml/ns/persistence">    
    <persistence-unit name="local" transaction-type="RESOURCE_LOCAL" >
    </persistence-unit>
</persistence>

我的 ARepositoryTest-context.xml

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:jpa="http://www.springframework.org/schema/data/jpa"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jdbc="http://www.springframework.org/schema/jdbc"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.0.xsd
     http://www.springframework.org/schema/data/jpa 
     http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
     http://www.springframework.org/schema/jdbc
 http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd"> 

    <context:annotation-config /> 
    <context:component-scan base-package="my.package"/>

    <import resource="classpath:/SpringBeans.xml"/>

</beans>

还有我的 SpringBeans.xml

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:jpa="http://www.springframework.org/schema/data/jpa"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jdbc="http://www.springframework.org/schema/jdbc"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.0.xsd
     http://www.springframework.org/schema/data/jpa 
     http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
     http://www.springframework.org/schema/jdbc
 http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd"> 

    <context:annotation-config /> 

    <jpa:repositories base-package="my.package.dao" />

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
        </property>
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
      <property name="persistenceUnitName" value="local"/>
      <property name="dataSource" ref="dataSource" />
      <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true"/>
                <property name="generateDdl" value="true" />
                <property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect"/>
                <property name="database" value="HSQL" />               
            </bean>
        </property>
        <property name="jpaPropertyMap">
            <map>
                <entry key="hibernate.show_sql" value="true" />
            </map>
        </property>
    </bean>

    <bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
        <property name="driverClassName" value="org.hsqldb.jdbcDriver" />
        <property name="url" value="jdbc:hsqldb:file:${user.home}/data;shutdown=true" />
        <property name="username" value="sa" />
        <property name="password" value="" />
    </bean>

    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/> 

</beans>

编辑:添加版本号和 xml 文件


编辑:对于 JB Nizet 的回答 如果我添加到 A 类

public void addB( B b ) {

    this.b.add( b );
}

并调整测试用例

@Test( groups = { "integration" } )
public void testSaveWithA() {

    A a = new A();
    aRepository.save( a );

    B b = new B();
    a.addB( b );
    aRepository.saveAndFlush( a );

    A findOne = aRepository.findOne( a.getId() );
    Assert.assertEquals( findOne.getB().size(), 1 );

}

测试通过 但是在 hsql 文件中,A 和 B 之间没有链接:

INSERT INTO A VALUES(1)
INSERT INTO B VALUES(1,NULL)

因此它无法在其他事务中正确选择它。

如果我在 A 中扩展新的 mMethod

public void addB( B b ) {

    this.b.add( b );
    b.setA( this );
}

刷新或提交时发生异常

java.lang.StackOverflowError
    at java.util.HashMap$KeyIterator.<init>(HashMap.java:926)
    at java.util.HashMap$KeyIterator.<init>(HashMap.java:926)
    at java.util.HashMap.newKeyIterator(HashMap.java:940)
    at java.util.HashMap$KeySet.iterator(HashMap.java:974)
    at java.util.HashSet.iterator(HashSet.java:170)
    at java.util.AbstractSet.hashCode(AbstractSet.java:122)
    at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:429)
    at my.package.A.hashCode(A.java:17)
    at my.package.B.hashCode(B.java:13)
    at java.util.AbstractSet.hashCode(AbstractSet.java:126)
    at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:429)
    at my.package.A.hashCode(A.java:17)
    at my.package.B.hashCode(B.java:13)
    ...

Linenumbers A.java:17 和 B.java:13 是放置 Lombok 的 @Data 注释的位置,生成我的 getter 和 setter。

通过使用 Lomboks @EqualsAndHashCode( exclude = { "b" } ) 删除对 lombok 的 hashCode 和 equals / 的依赖来解决

【问题讨论】:

    标签: java hibernate spring-data


    【解决方案1】:

    您的测试使用单个会话在单个事务中运行。因此,当您执行aRepository.findOne(a.getId()) 时,Hibernate 会返回已经在其一级缓存中的 A。而且由于您忘记将 B 添加到 A 中的 B 集合中,因此该集合仍然是空的。

    您有责任维护对象图的连贯性。如果你做b.setA(a),你也应该做a.getBs().add(b)。最好的办法是把这两个操作封装到A中的一个方法addB(B b)中,将B加入集合,初始化B.a

    【讨论】:

    • 我明白你的意思,但我没有完成初始化。我做了一个方法 A#addB(B b) 并在那里将 b 添加到集合中。现在 A 和 B 都存储到数据库中,但是 B 缺少对 A 的引用。如果我尝试另外 b.setA(a) 我遇到了 java.lang.StackOverflowError 我错过了什么?
    • 通过编辑您的问题(addB() 和 setA())向我们展示这两种方法的代码。
    • 我在问题末尾添加了我的更改
    • 我已经更改了 hashCode 和 equals 方法以忽略对 b 的引用,现在它可以工作了,我的错,但是在这里写下问题让我看到了这个错误。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-20
    • 1970-01-01
    • 2015-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-23
    相关资源
    最近更新 更多