将 AbstractTransactionalDataSourceSpringContextTests 与 Hibernate & 一起使用DbUnit - 找不到插入的数据

发布于 2024-09-08 03:20:29 字数 5417 浏览 6 评论 0原文

全部, 我正在尝试为使用 Hibernate 的 Dao 编写单元测试。我也在使用 Spring,因此我尝试扩展 AbstractTransactionalDataSourceSpringContextTests,并在 onSetUpInTransaction 方法中的每个测试之前使用 DBUnit 将数据插入数据库。

从我的日志中,我可以看到 DbUnit 能够成功地将数据插入 onSetUpInTransaction 中。但是,当我运行使用 Dao(因此使用 Hibernate)的测试方法来尝试访问该数据 (testGetPersonById2) 时,找不到数据,即使所有这些应该发生在同一笔交易。测试方法完成运行(失败)后,我从 AbstractTransactionalDataSourceSpringContextTests 中看到日志语句,表明事务确实已正确回滚。

看起来 onSetUpInTransaction 和 Hibernate 会话必须使用不同的事务,但我不明白为什么。有人有这样的例子吗?关于我缺少什么的建议?

这是我到目前为止所得到的:

public class PersonDaoTest extends AbstractTransactionalDataSourceSpringContextTests{

    private Log logger = LogFactory.getLog(PersonDaoTest.class);

    private PersonDaoImpl personDao;

    @Override
    public void onSetUpInTransaction() throws Exception {
    // Load test data using DBUnit
    super.onSetUpBeforeTransaction();
        DataSource ds = jdbcTemplate.getDataSource()
    Connection con = DataSourceUtils.getConnection(ds);
    IDatabaseConnection dbUnitCon = new DatabaseConnection(con);
    DatabaseConfig config = dbUnitCon.getConfig();
    config.setFeature("http://www.dbunit.org/features/qualifiedTableNames",
        true);

        //This dataset contains a single entry in the Persons table,
        // a new person with Id = 998877665, it gets inserted successfully
    IDataSet dataSet = new FlatXmlDataSet(new FileInputStream(
        "./PersonDaoTest.xml"));
    logger.warn("dataSet = " + dataSet);
    try {
        DatabaseOperation.REFRESH.execute(dbUnitCon, dataSet);
        SessionFactoryUtils.getSession(getSessionFactory(), false).flush();

    } finally {
        DataSourceUtils.releaseConnection(con, ds);
    }

    }

     //This test PASSES, because the Person with Id = 9 already
     //exists in the database, it does not rely on the data being set up in the        
     // onSetUpInTransaction method 
     @Test
     public void testGetPersonById() {

     Person person = personDao.findById(9L);
     assertNotNull("person should not be null", person);

     }

    //This test FAILS at the assertNotNull line, because
    //no Person with Id = 998877665 exists in the database,
    //even though that Person was inserted 
    //in the onSetUpInTransaction  method - it seems
    //that hibernate cannot see that insertion.
    @Test
    public void testGetPersonById2() {

    Person person = personDao.findById(998877665L);
    assertNotNull("person should not be null", person);

    }

更新:这是我的 spring 配置:

<bean id="propertyConfigurer"       class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:jdbc.properties</value>
            </list>
        </property>
    </bean>

<bean id="dataSource" class="com.p6spy.engine.spy.P6DataSource">
  <constructor-arg>
    <bean id="basicDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
   <property name="driverClassName">
     <value>${jdbc.driverClassName}</value>
    </property>
    <property name="url">
       <value>${jdbc.url}</value>
    </property>
    <property name="username">
       <value>${jdbc.username}</value>
    </property>
     <property name="password">
       <value>${jdbc.password}</value>
      </property>
   </bean>
  </constructor-arg>
</bean>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>


<!-- Hibernate SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource"><ref bean="dataSource"/></property>

        <property name="configLocation">
             <value>classpath:hibernate.cfg.xml</value>
        </property>

        <property  name="configurationClass">
            <value>org.hibernate.cfg.AnnotationConfiguration</value>
        </property>

        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
                <prop key="hibernate.cache.use_query_cache">false</prop>
                <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
                <prop key="hibernate.cache.query_cache_factory">org.hibernate.cache.StandardQueryCacheFactory</prop>
            </props>
        </property>
    </bean>

    <!-- The Hibernate interceptor 
    <bean id="hibernateInterceptor" class="org.springframework.orm.hibernate3.HibernateInterceptor">
        <property name="sessionFactory"><ref bean="sessionFactory"/></property>
    </bean>-->

     <bean id="personDao" class="my.dao.PersonDaoImpl">
        <property name="sessionFactory"><ref bean="sessionFactory"/></property>         
    </bean> 

All,
I'm attempting to write a unit test for a Dao that uses Hibernate. I'm also using Spring, so I'm trying to extend AbstractTransactionalDataSourceSpringContextTests and also use DBUnit to insert data into the database before each test in the onSetUpInTransaction method.

From my logs, I can see that DbUnit is able to successfully insert the data in onSetUpInTransaction just fine. However, when I run a test method that uses the Dao (and therefore, Hibernate) to try to access that data (testGetPersonById2), the data isn't found, even though all this should be happening in the same transaction. After the test method finishes running (it fails), I see the log statement from the AbstractTransactionalDataSourceSpringContextTests that the transaction does get rolled back correctly.

It seems like the onSetUpInTransaction and Hibernate session must be using different transactions, but I can't figure out why. Does anyone have an example of something like this working? Advice on what I'm missing?

Here's what I've got so far:

public class PersonDaoTest extends AbstractTransactionalDataSourceSpringContextTests{

    private Log logger = LogFactory.getLog(PersonDaoTest.class);

    private PersonDaoImpl personDao;

    @Override
    public void onSetUpInTransaction() throws Exception {
    // Load test data using DBUnit
    super.onSetUpBeforeTransaction();
        DataSource ds = jdbcTemplate.getDataSource()
    Connection con = DataSourceUtils.getConnection(ds);
    IDatabaseConnection dbUnitCon = new DatabaseConnection(con);
    DatabaseConfig config = dbUnitCon.getConfig();
    config.setFeature("http://www.dbunit.org/features/qualifiedTableNames",
        true);

        //This dataset contains a single entry in the Persons table,
        // a new person with Id = 998877665, it gets inserted successfully
    IDataSet dataSet = new FlatXmlDataSet(new FileInputStream(
        "./PersonDaoTest.xml"));
    logger.warn("dataSet = " + dataSet);
    try {
        DatabaseOperation.REFRESH.execute(dbUnitCon, dataSet);
        SessionFactoryUtils.getSession(getSessionFactory(), false).flush();

    } finally {
        DataSourceUtils.releaseConnection(con, ds);
    }

    }

     //This test PASSES, because the Person with Id = 9 already
     //exists in the database, it does not rely on the data being set up in the        
     // onSetUpInTransaction method 
     @Test
     public void testGetPersonById() {

     Person person = personDao.findById(9L);
     assertNotNull("person should not be null", person);

     }

    //This test FAILS at the assertNotNull line, because
    //no Person with Id = 998877665 exists in the database,
    //even though that Person was inserted 
    //in the onSetUpInTransaction  method - it seems
    //that hibernate cannot see that insertion.
    @Test
    public void testGetPersonById2() {

    Person person = personDao.findById(998877665L);
    assertNotNull("person should not be null", person);

    }

UPDATE: Here's my spring config:

<bean id="propertyConfigurer"       class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:jdbc.properties</value>
            </list>
        </property>
    </bean>

<bean id="dataSource" class="com.p6spy.engine.spy.P6DataSource">
  <constructor-arg>
    <bean id="basicDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
   <property name="driverClassName">
     <value>${jdbc.driverClassName}</value>
    </property>
    <property name="url">
       <value>${jdbc.url}</value>
    </property>
    <property name="username">
       <value>${jdbc.username}</value>
    </property>
     <property name="password">
       <value>${jdbc.password}</value>
      </property>
   </bean>
  </constructor-arg>
</bean>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>


<!-- Hibernate SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource"><ref bean="dataSource"/></property>

        <property name="configLocation">
             <value>classpath:hibernate.cfg.xml</value>
        </property>

        <property  name="configurationClass">
            <value>org.hibernate.cfg.AnnotationConfiguration</value>
        </property>

        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
                <prop key="hibernate.cache.use_query_cache">false</prop>
                <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
                <prop key="hibernate.cache.query_cache_factory">org.hibernate.cache.StandardQueryCacheFactory</prop>
            </props>
        </property>
    </bean>

    <!-- The Hibernate interceptor 
    <bean id="hibernateInterceptor" class="org.springframework.orm.hibernate3.HibernateInterceptor">
        <property name="sessionFactory"><ref bean="sessionFactory"/></property>
    </bean>-->

     <bean id="personDao" class="my.dao.PersonDaoImpl">
        <property name="sessionFactory"><ref bean="sessionFactory"/></property>         
    </bean> 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

萌化 2024-09-15 03:20:29

我花了更多的时间来解决这个问题,但在尝试使用 onSetUpInTransaction 方法时却找不到任何有效的方法。我最终转而使用 onSetUpBeforeTransaction 和 onTearDownAfterTransaction 。这并不完全理想,因为 onSetUpBeforeTransaction 方法最终会将其数据插入提交到数据库,然后必须在 onTearDownAfterTransaction 中清除该数据。但是,测试本身仍然可以根据需要插入和更新数据,并将这些更改全部回滚,因为每个测试仍然在其自己的事务中运行。因此,当测试插入新数据时,我不需要做任何特殊的清理工作,这意味着无论如何我都实现了我的目标之一!

I spent some more time with this, and never was able to find anything that worked when trying to use the onSetUpInTransaction method. I ended up switching over to using onSetUpBeforeTransaction and onTearDownAfterTransaction instead. It's not exactly ideal, because the onSetUpBeforeTransaction method does end up committing its data insertions to the database, and that data must then be cleaned up in onTearDownAfterTransaction. However, the tests themselves can still insert and update data all they want and have those changes all rolled back, since each test does still operate in its own transaction. So, I don't have to do anything special to clean up when a test inserts new data, which means I met one of my goals anyway!

晨光如昨 2024-09-15 03:20:29

我有类似的问题。这是我解决问题的方法。
我向我的抽象测试用例类添加了代码
然后我添加了一个名为“dataSource”的数据源,它允许我使用它来插入测试数据并使用该数据源创建测试 sql。
各个数据源 datasource1 和 datasource2 已正确注入到我的 dao beans 中,没有任何问题。

@Override
protected String[] getConfigLocations() 
{
    setAutowireMode(AUTOWIRE_BY_NAME);
    setDependencyCheck(false);
    return new String[] { "classpath:configuration/myappxxx-test-application-context.xml" };
}

I had a similar problem. here is how I solved it.
I added a code to my abstract testcase class
then I added a datasource with the name "dataSource" which allowed me to use it to insert my test data and create my test sqls using that data source.
The individual datasources datasource1 and datasource2 were correctly injected into my dao beans without any issue.

@Override
protected String[] getConfigLocations() 
{
    setAutowireMode(AUTOWIRE_BY_NAME);
    setDependencyCheck(false);
    return new String[] { "classpath:configuration/myappxxx-test-application-context.xml" };
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文