2013-04-06 11 views
1

我使用以下框架:我有Hibernate緩存或映射錯誤嗎?

  • 休眠4.2.0.Final
  • 春3.2.2.RELEASE
  • 春數據JPA 1.1.0.RELEASE
  • HSQL 2.2.9
  • TestNG的6.1.1

我有2個實體:

實體答:

@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 

} 

和我做了春天的數據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] 

而我不明白爲什麼。映射中是否存在缺失,或者是否必須清除休眠緩存? 我看到沒有新的選擇查詢,所以hibernate正在緩存A對象 - 但是不應該將引用從A更新到緩存中的Bs?這裏

隨着更多的信息是我的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答案 如果我添加到

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) 

所以它不會能夠在其他交易中正確選擇它。

如果我在一個

public void addB(B b) { 

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

沖洗或提交時例外occures拓展新mMethod

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是在@Data Lombok的註釋被放置在生成我的getters和setter。

通過去除依賴性解決龍目爲的hashCode和等於/通過使用Lomboks @EqualsAndHashCode(排除= {「B」})

回答

2

你的測試在單個事務中運行,使用單個會話。所以當你執行aRepository.findOne(a.getId())時,Hibernate會返回已經在第一級緩存中的A.而且由於您忘記將B添加到A中的一組B中,此集合仍然是空的。

維護對象圖的一致性是您的責任。如果你做b.setA(a),你也應該做a.getBs().add(b)。最好的方法是將這兩個操作封裝在A中的addB(B b)方法中,該方法將B添加到集合中並初始化B.a

+0

我在這裏看到你的觀點,但是我沒有完成初始化。我做了一個方法A#addB(B b),並在那裏將b添加到Set中。現在,A和B都存儲在數據庫中,但是B缺少對A的引用。如果我嘗試另外b.setA(a),我碰到了一個java.lang.StackOverflowError我是否缺少了一些東西? – Thomas 2013-04-07 10:21:03

+0

通過編輯問題(addB()和setA())向我們展示這兩種方法的代碼。 – 2013-04-07 10:32:11

+0

我在問題的末尾添加了我的更改 – Thomas 2013-04-07 10:46:23