2012-02-22 119 views
0

我有一套系統測試使用Spring的JUnit運行,數據庫的配置是這樣的:刷新數據庫連接

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> 
    <property name="driverClassName" value="org.postgresql.Driver" /> 
    <property name="url" value="${clustercatalog.jdbc.url}" /> 
    <property name="username" value="${clustercatalog.jdbc.username}" /> 
    <property name="password" value="${clustercatalog.jdbc.password}" /> 
    <property name="initialSize" value="5" /> 
    <property name="maxActive" value="50" /> 
    <property name="poolPreparedStatements" value="true" /> 
    <property name="maxOpenPreparedStatements" value="100" /> 
</bean> 

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
    <property name="dataSource" ref="dataSource" /> 
    <property name="packagesToScan" value="com.xxx" /> 
    <property name="hibernateProperties"> 
     <props> 
      <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop> 
      <prop key="hibernate.show_sql">${jdbc.show.sql}</prop> 
      <prop key="hibernate.id.new_generator_mappings">true</prop> 
     </props> 
    </property> 
    <property name="namingStrategy" ref="namingStrategy" /> 
</bean> 

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactory" /> 
</bean> 
<tx:annotation-driven /> 

的測試用例中,我運行一些的設置bash腳本,該腳本從先前完成的備份中在底層PostgreSQL數據庫上運行pg_restore。這是因爲我需要在每個測試方法之前使數據庫的狀態保持一致。這種還原是在用@BeforeTransaction進行註解的方法中完成的。

測試類都被註解

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration({ "/systemTests-applicationContext.xml", "/applicationContext.xml" }) 
@TransactionConfiguration(defaultRollback = false) 
@Transactional() 

在測試中,當我執行使用當前Hibernate的Session的代碼,它不會看到已恢復的表。當我重新啓動整個測試然後看到他們,但顯然這是我想要的,但它證明了數據庫是好的,但是當我做pg_restore時,Spring/Hibernate丟失了。我得到SQLGrammarException表,該表不存在。

我正在尋找一種方法來手動重新連接到數據庫。我怎樣才能做到這一點?我應該以某種方式在sessionFactory或某些Spring組件上執行此操作嗎?

回答

2

好的,我解決了這個問題。看起來Spring和Hibernate都不知道DB中發生的變化,並且如果DBCP池中有任何連接,它們將被重用,然後會發生錯誤,因爲連接下方的模式已更改。所以我想到在重置數據庫時測試過程中戳的地方是提供給Hibernate SessionFactory的javax.sql.DataSource對象。 DBCP BasicDataSource不具備此功能,因此我:

  1. 爲dataSource bean創建了我自己的包裝器。
  2. 標誌着bean作爲原型的範圍,所以我不會有構建它自己,每當我需要一個新的
  3. 添加一個刷新方法,其調用ApplicationContext的包裝類(自動裝配到包裝類)的新的bean實例
  4. 注入包裝器bean加入到Hibernate的SessionFactory
  5. 自動裝配包裝上,以測試類,當我需要在測試中調用刷新方法

代碼如下:

@Component 
public class RefreshableDataSource implements DataSource { 

    @Autowired 
    DataSource dataSource; 
    @Autowired 
    ApplicationContext applicationContext; 

    public void refresh() { 
    dataSource = (DataSource) applicationContext.getBean("dataSource"); 
    } 

    @Override 
    public Connection getConnection() throws SQLException { 
    return dataSource.getConnection(); 
    } 

    ...other DataSource methods ... 
} 

的applicationContext.xml:

<bean id="dataSource" scope="prototype" class="org.apache.commons.dbcp.BasicDataSource"> 
    <property name="driverClassName" value="org.postgresql.Driver" /> 
      ...... 
</bean> 

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
    <property name="dataSource" ref="refreshableDataSource" /> 
    <property name="packagesToScan" value="com.xxx" /> 
    <property name="hibernateProperties"> 
     <props> 
      <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop> 
      <prop key="hibernate.show_sql">${jdbc.show.sql}</prop> 
      <prop key="hibernate.id.new_generator_mappings">true</prop> 
     </props> 
    </property> 
    <property name="namingStrategy" ref="namingStrategy" /> 
</bean>