Перезагрузите соединение с базой данных в тесте Spring + Hibernate - PullRequest
0 голосов
/ 23 февраля 2012

У меня есть набор системных тестов, использующих Spring Runner 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, которые запускают pg_restoreбаза данных PostgreSQL из ранее сделанной резервной копии.Это потому, что мне нужно, чтобы одно и то же состояние базы данных было одинаковым перед каждым методом тестирования.Это восстановление выполняется методом, аннотированным @BeforeTransaction.

Тестовый класс помечается

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

. В тесте, когда я выполняю код, использующий текущий сеанс гибернации, он не видит восстановленные таблицы.Когда я перезапускаю весь тест, он видит их, но, очевидно, это то, что я хочу, но это доказывает, что БД в порядке, но Spring / Hibernate потерялся, когда я сделал pg_restore.Я получаю SQLGrammarException, что таблица не существует.

Я ищу способ вручную перезапустить соединение с БД.Как я могу этого достичь?Должен ли я сделать это как-то на sessionFactory или некоторых компонентах Spring?

1 Ответ

2 голосов
/ 25 февраля 2012

ОК, я решил проблему.Похоже, что Spring и Hibernate не знают об изменениях, происходящих в БД, и если в пуле DBCP есть какие-либо соединения, они используются повторно, и затем возникает ошибка, потому что схема изменилась под этим соединением.Поэтому я решил, что во время теста, когда я перезагружаю БД, нужно тыкать в объект javax.sql.DataSource, предоставленный Hibernate SessionFactory.DBCP BasicDataSource не имеет этой возможности, поэтому я:

  1. создал свою собственную оболочку для bean-компонента dataSource.
  2. пометил bean-компонент как область действия прототипа, поэтому мне не придется создавать его самому, каждый раз, когда мне нужен новый
  3. добавлял метод обновления в класс-оболочку, который вызывает applicationContext (autowired toкласс-обертка) для нового экземпляра компонента
  4. внедрил компонент-оболочку в sessionFactory Hibernate
  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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...