`
dengyin2000
  • 浏览: 1210010 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

使用Spring AbstractTransactionalDataSourceSpringContextTests测试

阅读更多
在使用AbstractTransactionalDataSourceSpringContextTests这个作为测试hibernate的Service时,遇到这样的一个问题。 就是一定要在代码中显示的调用session.flush()。 更改操作才能立即看到。。

比如

	public void testDeleteBillingEntity(){
		getBillingEntityService().deleteBillingEntity(1);
		assertEquals("BillingEntity(1) should be not existed", getJdbcTemplate().queryForInt("SELECT COUNT(*) FROM BILLING_ENTITY WHERE ID=1"), 0);
	}


如果我不在getBillingEntityService().deleteBillingEntity(1) 方法里面调用sesson.flush()的话。 这个测试是失败的。但是在真是环境中的话不调用session.flush()是能行的。Hibernate 默认的是autoFlush 大家应该也遇到相同的问题吧。 是如何解决的?

谢谢
分享到:
评论
29 楼 dengyin2000 2007-05-15  
zhour560 写道
我也遇到Spring AbstractTransactionalDataSourceSpringContextTests测试不可以回滚的问题。数据库是MYSQL。在测试里面新增记录的时候,竟然加数据库里面去了。而且更新和删除都可以回滚的!
public abstract class SpringTestCaseBase extends AbstractTransactionalDataSourceSpringContextTests {
protected SimpleDateFormat sdf;

public SpringTestCaseBase() {
// query the protected variables to implement denpendency injection automatically,
// so we don't need to write settor and gettor methods anymore.
this.setPopulateProtectedVariables(true);

sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getDefault());
}

protected String[] getConfigLocations() {
return new String[] { "file:web/WEB-INF/applicationContext*.xml",
          "file:web/WEB-INF/test-ApplicationContext*.xml"};
    }

protected void flushSession(){
SessionFactory sessionFactory = (SessionFactory)applicationContext.getBean("sessionFactory");  
        sessionFactory.getCurrentSession().flush();
    }
}
这是我测试基类。


看看你mysql数据库是什么类型的。 ISM类型的应该不能回滚,因为不支持事务。 换成innodb
28 楼 zhour560 2007-05-15  
我也遇到Spring AbstractTransactionalDataSourceSpringContextTests测试不可以回滚的问题。数据库是MYSQL。在测试里面新增记录的时候,竟然加数据库里面去了。而且更新和删除都可以回滚的!
public abstract class SpringTestCaseBase extends AbstractTransactionalDataSourceSpringContextTests {
protected SimpleDateFormat sdf;

public SpringTestCaseBase() {
// query the protected variables to implement denpendency injection automatically,
// so we don't need to write settor and gettor methods anymore.
this.setPopulateProtectedVariables(true);

sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getDefault());
}

protected String[] getConfigLocations() {
return new String[] { "file:web/WEB-INF/applicationContext*.xml",
          "file:web/WEB-INF/test-ApplicationContext*.xml"};
    }

protected void flushSession(){
SessionFactory sessionFactory = (SessionFactory)applicationContext.getBean("sessionFactory");  
        sessionFactory.getCurrentSession().flush();
    }
}
这是我测试基类。
27 楼 dengyin2000 2007-05-11  
用session.get试试
26 楼 晨星★~雨泪 2007-05-11  
我总觉得既然已删除 那么查出的结果应为NULL 才对,为什么要报错?
如果我 用 Hibernate findByid 去查一个数据表里没有的记录 那不是老抛异常.
25 楼 spiritfrog 2007-05-10  
晨星★~雨泪 写道
我用 Hibernate delete 后 用Spring JdbcTemplate 查被删的记录还是存在,可用 Hibernate findByid 就会报 该记录已删 的错误.郁闷

hibernate delete只是在缓存中将某个持久对象给标记成删除的,但没有flunsh就实际没有执行删除操作,而JdbcTemplate不在session控制之下,因此还能从数据库找到标记为删除的记录。当然,被标记为删除的记录,再次通过hibernate来查找就会抛出异常,说已经被删除了。
24 楼 spiritfrog 2007-05-10  
这里是需要调用session的flunsh的,因为getJdbcTemplate().queryForInt方法不会flunsh缓存。
23 楼 晨星★~雨泪 2007-05-10  
我用 Hibernate delete 后 用Spring JdbcTemplate 查被删的记录还是存在,可用 Hibernate findByid 就会报 该记录已删 的错误.郁闷
22 楼 温柔一刀 2007-04-14  
dada 写道
我不认为测试一定要直接操作数据库,尤其是用hibernate的时候。


如果用了hibernate

测试的时候用hsqldb就可以了
21 楼 dada 2007-04-11  
dengyin2000 写道
刚刚看了下,确实是拿的session cache中的对象, 根本没有发送select 语句

这段代码的本意就是判断session中的对象是否被删除了。
前头漏了段
public void testDelete() {
    Sample sample = dao.get(new Long(1));
    dao.delete(sample);
    Object obj = dao.get(new Long(1));
    AssertNull(obj);
}

我不认为测试一定要直接操作数据库,尤其是用hibernate的时候。
20 楼 dengyin2000 2007-04-11  
刚刚看了下,确实是拿的session cache中的对象, 根本没有发送select 语句
19 楼 dengyin2000 2007-04-11  
dada 写道
dengyin2000 写道
总结下, 应该commit transaction才会触发session 的flush的吧。

刚才看了下AbstractTransactionalDataSourceSpringContextTests这个类。他是在onSetup的时候开始transaction 然后在onTeardown时commit transaction。 所以如果不显示调用session.flush的话,table里面是不会有变化的。所以我的设想应该是正确的,flushCurrentSession()方法里面拿的是同一个session。


想要看到数据变化的话 在你的测试方法里面调用下flushCurrentSession()方法就行。。

    protected SessionFactory getSessionFactory(){
    	return (SessionFactory) getApplicationContext().getBean("sessionFactory");
    }
    
    protected void flushCurrentSession(){
    	Session session = SessionFactoryUtils.getSession(getSessionFactory(), false);
    	if (session !=null){
    		session.flush();
    	}
    }


我觉得改变测试方法比较好:
public void testDelete() {
    service.delete(new Long(1));
    Object obj = service.get(new Long(1));
    assertNull(obj);
}


刚刚又想到了你这样会不会有问题。看下面的代码,我把delete变成了save

public void testSave() {
    service.save(new Long(1));
    Object obj = service.get(new Long(1));
    assertNull(obj);
}


因为在testSave中是在一个session中, 所以service.get的话可能根本不会读数据库里面的值, 而是拿的session cache中的?
18 楼 dengyin2000 2007-04-11  
Godlikeme 写道
Godlikeme 写道
每次调用,应该是取的不同的session,这样是不对的,参见HibernateTemaplate.executeWithSession

这个问题我看错了,原来问题是jdbctemplate.execute(),不是不同session的问题。
只能显示调用sessionFlush了,hibernateTemplate和jdbcTemplate一块用,这样不一致性的问题就会一直存在。


是的  我没有发现,hibernateTemplate有executeWithSession这个方法。
正规的话 当然是应该用jdbc来测试的。 
17 楼 Godlikeme 2007-04-11  
Godlikeme 写道
每次调用,应该是取的不同的session,这样是不对的,参见HibernateTemaplate.executeWithSession

这个问题我看错了,原来问题是jdbctemplate.execute(),不是不同session的问题。
只能显示调用sessionFlush了,hibernateTemplate和jdbcTemplate一块用,这样不一致性的问题就会一直存在。
16 楼 Godlikeme 2007-04-11  
tsingn 写道
Godlikeme 写道
每次调用,应该是取的不同的session,这样是不对的,参见HibernateTemaplate.executeWithSession
同意!
但是不知道为什么用不同的session flush一下也会起作用?

flush后session是与数据库同步的,因为测试不是多线程,session之间就不会出现不一致的情况。
15 楼 dengyin2000 2007-04-11  
dada 写道
dengyin2000 写道
总结下, 应该commit transaction才会触发session 的flush的吧。

刚才看了下AbstractTransactionalDataSourceSpringContextTests这个类。他是在onSetup的时候开始transaction 然后在onTeardown时commit transaction。 所以如果不显示调用session.flush的话,table里面是不会有变化的。所以我的设想应该是正确的,flushCurrentSession()方法里面拿的是同一个session。


想要看到数据变化的话 在你的测试方法里面调用下flushCurrentSession()方法就行。。

    protected SessionFactory getSessionFactory(){
    	return (SessionFactory) getApplicationContext().getBean("sessionFactory");
    }
    
    protected void flushCurrentSession(){
    	Session session = SessionFactoryUtils.getSession(getSessionFactory(), false);
    	if (session !=null){
    		session.flush();
    	}
    }


我觉得改变测试方法比较好:
public void testDelete() {
    service.delete(new Long(1));
    Object obj = service.get(new Long(1));
    assertNull(obj);
}


我有遇到你这种情况, 一个同事使用jdbc去验证的时候 会有问题, 但是我用service去拿的话 就能通过。 最后发现我这里发送了update语句,而用jdbc去验证的话并没有flush。 我不觉得你上面的方式好。 因为我这种方式对于使用jdbc或者其他方式去验证都是有效的, 而且如果我没有get find方法呢? 我还要为测试去加多这样的方法?
14 楼 dada 2007-04-11  
dengyin2000 写道
总结下, 应该commit transaction才会触发session 的flush的吧。

刚才看了下AbstractTransactionalDataSourceSpringContextTests这个类。他是在onSetup的时候开始transaction 然后在onTeardown时commit transaction。 所以如果不显示调用session.flush的话,table里面是不会有变化的。所以我的设想应该是正确的,flushCurrentSession()方法里面拿的是同一个session。


想要看到数据变化的话 在你的测试方法里面调用下flushCurrentSession()方法就行。。

    protected SessionFactory getSessionFactory(){
    	return (SessionFactory) getApplicationContext().getBean("sessionFactory");
    }
    
    protected void flushCurrentSession(){
    	Session session = SessionFactoryUtils.getSession(getSessionFactory(), false);
    	if (session !=null){
    		session.flush();
    	}
    }


我觉得改变测试方法比较好:
public void testDelete() {
    service.delete(new Long(1));
    Object obj = service.get(new Long(1));
    assertNull(obj);
}
13 楼 tsingn 2007-04-11  
AbstractTransactionalDataSourceSpringContextTests里面的tearDown有两个方法:onTearDownInTransaction和onTearDownAfterTransaction
所以你可以试着把flush的操作放在onTearDownInTransaction里面看看,这样你不用每次都要在测试方法里面调用了!
完了把测试结果贴一下,呵呵。
12 楼 dengyin2000 2007-04-11  
总结下, 应该commit transaction才会触发session 的flush的吧。

刚才看了下AbstractTransactionalDataSourceSpringContextTests这个类。他是在onSetup的时候开始transaction 然后在onTeardown时commit transaction。 所以如果不显示调用session.flush的话,table里面是不会有变化的。所以我的设想应该是正确的,flushCurrentSession()方法里面拿的是同一个session。


想要看到数据变化的话 在你的测试方法里面调用下flushCurrentSession()方法就行。。

    protected SessionFactory getSessionFactory(){
    	return (SessionFactory) getApplicationContext().getBean("sessionFactory");
    }
    
    protected void flushCurrentSession(){
    	Session session = SessionFactoryUtils.getSession(getSessionFactory(), false);
    	if (session !=null){
    		session.flush();
    	}
    }
11 楼 tsingn 2007-04-11  
dada 写道
一个测试方法一个transaction,assertEquals这里session还没有关闭,所以你测试不会通过。

这样说就能够解释了,我一直以为session在dao.delete()方法结束后就关闭了。哈哈
10 楼 dada 2007-04-11  
一个测试方法一个transaction,assertEquals这里session还没有关闭,所以你测试不会通过。

相关推荐

Global site tag (gtag.js) - Google Analytics