2017-04-24 100 views
0

我正在使用Hibernate 3.5.6-Final進行生產的Oracle數據庫和集成測試的H2數據庫。 Hibernate映射的ID創建看起來像這樣延伸EasyPersistentObject每一個實體:如何重置Hibernate序列生成器?

@MappedSuperclass 
public class EasyPersistentObject implements Serializable { 

@Id 
@SequenceGenerator(name = "hibernate_seq", sequenceName = "hibernate_id_seq", allocationSize = 1) 
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "hibernate_seq") 
protected Integer id; 

每個JUnit的集成測試我與

new SchemaExport(configuration).create(false, true); 

一切刪除數據庫中的所有數據前,直到我增加了工作正常用於序列生成的分配大小。舉例來說,當插入測試數據時,10將會破壞與UniqueKeyConstraintViolations的多項測試。

例如:

  1. 測試1:創建8個測試對象(Hibernate有ID值9,10仍然分配)
  2. 重新創建數據庫
  3. 的Test2:創建12個測試對象(Hibernate使用圖9和10對於ID,然後從數據庫序列中加載新的ID,同時重置(1-10),嘗試插入第二個ID爲9的實體時失敗)

所以我的問題:有沒有一種方法可以在每次測試之前重置Hibernates分配的ID以及?

增加: 我不使用的PersistenceManager從JPA但純粹的SessionFactory這是這樣創建的:

@Bean(name = "easySF") 
public SessionFactory easySessionFactory(@Qualifier("easyConfig") AnnotationConfiguration configuration) { 
    configuration.setInterceptor(new HibernateInterceptor()); 
    return configuration.buildSessionFactory(); 
} 

@Bean(name = "easyConfig") 
protected AnnotationConfiguration easyHibernateConfiguration() { 
    AnnotationConfiguration configuration = new AnnotationConfiguration(); 
    configuration.setProperties(createHibernateProperties()); 
    configuration.addResource("NamedQueries.hbm.xml"); 
    for (Class annotatedClass : getAnnotatedClasses()) { 
     configuration.addAnnotatedClass(annotatedClass); 
    } 
    configuration.setListener("post-load", new PreloadEventListener()); 
    return configuration; 
} 

我真的需要重新加載我的整個Spring上下文來獲取Hibernate的標識生成器reseted?

回答

1

我面臨同樣的問題,並沒有找到一個inbuild辦法做到這一點。我們使用hibernate 4.2.7。

在深入調試休眠後,我最終擴展了序列生成器。我們創建使用標準序列發生器實體:

@SequenceGenerator(name = "SomeSeq", sequenceName = "DB_SEQ", allocationSize = 50) 

的Hibernate會爲每個實體org.hibernate.id.SequenceHiLoGenerator。 SequnceHiLoGenerator委託給OptimizerFactory.LegacyHiLoAlgorithmOptimizer實例。

爲了重置序列計數器並強制與數據庫序列同步,您必須重置LegacyHiLoAlgorithmOptimizer中的內部變量。不幸的是,這些變量是私人的,不可修改的。我試圖找到使用繼承的方式,但我沒有找到一個優雅的解決方案。最後,我
創建的SequenceHiLoGenerator的源副本,並用一個簡單的復位功能,擴展它:

public class ResetableIdGenerator extends SequenceGenerator { 
       public static int cycle = 0; // global, indicating current test cycle 
       protected int startingCycle = 0; // instance, indicating the test cycle the LegacyHiLoAlgorithmOptimizer was used the last time 
    [...] 
     public synchronized Serializable generate(final SessionImplementor session, Object obj) { 
      // create a new HiLoOptimizer if there's a new test cycle 
      if (startingCycle < cycle) { 
       hiloOptimizer = new OptimizerFactory.LegacyHiLoAlgorithmOptimizer(getIdentifierType().getReturnedClass(), 
         maxLo); 
       startingCycle = cycle; 
      } 
[....] 

修改實體使用自定義的生成:

@GenericGenerator(name = "SomeSeq", strategy = "yourpackage.ResetableIdGenerator", parameters = { 
     @Parameter(name = "sequence", value = "DB_SEQ"), @Parameter(name = "max_lo", value = "49") }) 

復位序列發生器插圖中測試(@before或@after):

// reset Hibernate Sequences 
ResetableIdGenerator.cycle++; 

我知道這不是一個好的解決方案 - 這是一個黑客攻擊。但它有效,也許有助於找到更好的解決方案。

編輯20170504:我最初的帖子包含一個錯誤:參數「sequenceName」和「allocationSize」是JPA參數。 GenericGenerator來自休眠。 而不是「sequenceName」你必須使用「序列」,而不是「分配大小」,你必須使用「max_lo」並將其設置爲allocationSize-1。 我更新了代碼示例。抱歉!

+0

感謝這個詳細的答案,這證實了我不想相信的東西。我將用int單個布爾值重置值,並用你的黑客解決它。太悲傷了,沒有乾淨的方法來做到這一點... – GreenTurtle

0

這將迫使休眠重新加載其ID發生器:

myEntityManagerFactory.close();

myEntityManagerFactory = Persistence.createEntityManagerFactory(...);

+0

Thx,但太傷心了,我們不在這個項目中使用普通的JPA。請在上面的問題中查看我的補充內容。 – GreenTurtle

1

也許解決方案之一是在新的sessionfactory中運行每個JUNIT測試。使用@Before@After如此開放和關閉會話工廠

優點

  • 你從第一

缺點序列發生器

  • 它需要幾秒鐘,所有JUNIT測試用例

更新

基於註釋的另一種方式是在每一個JUnit測試中@Before方法重置序列

ALTER SEQUENCE Test.sequence RESTART WITH 1 
+0

使用新的sessionfactory運行每個測試意味着一個Spring上下文重新加載,我擔心這太費時,因此不可行(上下文重新加載在此項目中需要大約15秒,並且有很多集成測試) – GreenTurtle

+0

@GreenTurtle可以您嘗試更新的答案,因爲JUNIT使用內存應該更快 – rajadilipkolli

+0

此聲明不適用於Oracle(可能不是H2)。但我試圖刪除並重新創建序列,但沒有任何效果。我使用createSQLQuery,而Hibernate沒有注意到序列中的機會...... :-( – GreenTurtle