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

AbstractTransactionalDataSourceSpringContextTests=鸡肋?

阅读更多
我用mysql做数据库,使用AbstractTransactionalDataSourceSpringContextTests测试时,发现根本没有写数据库,连错误都没有发生,直到我提交了事务才写数据库,并发现了错误。

springside的高人也说过:hibernate太奸诈了,如果全部默认回滚,只会在session里干活,一点不写数据库,达不到完全的测试效果。
http://www.springside.org.cn/docs/reference/UnitTest.htm

如果是这样的话,是否可以认为,AbstractTransactionalDataSourceSpringContextTests对hibernate来说,是个完全的鸡肋?因为不提交的话,事务完全回滚,根本不写数据库,连错误都找不出;提交的话,又破坏了数据。

如果不是鸡肋,那该如何改进?
分享到:
评论
15 楼 littcai 2007-04-12  
加一个拦截器,在方法结束后调用flush操作
14 楼 netfly 2006-12-27  
问题解决了,原来是我的数据库不支持事务,哈哈!谢谢大家的关注,springside误导了我,害人不浅呀。

MYSQL中只有INNODB和BDB类型的数据表才支持事务处理!其他的类型是不支持.
13 楼 Godlikeme 2006-12-26  
  protected ConfigurableApplicationContext loadContext(Object key) throws Exception {  
        setAutowireMode(AUTOWIRE_BY_NAME);  
       setDefaultRollback(false); 
        return (ConfigurableApplicationContext) ContainerFactory.newInstance((String) key, getResources());  
    }  
这个太明显了吧,还是setDefaultRollback(false)呢。
没有看到在任何地方做session的处理。
12 楼 netfly 2006-12-25  
我的代码,
先自己实现了一个容器,用自己的ContainerFactory来生成这个容器,再加入到SpringContext中去,代码如下:
public abstract class AbstractDaoTestCase extends AbstractTransactionalDataSourceSpringContextTests {
	/**
	 * 不同的应用程序必须指定不同的key值,也就是说不同的应用程序必须覆盖此方法
	 */
	@Override
	protected Object contextKey() {
		return Constants.FAMEWORK_CONTAINER_KEY;
	}
	
	@Override
	protected ConfigurableApplicationContext loadContext(Object key) throws Exception {
		setAutowireMode(AUTOWIRE_BY_NAME);
		setDefaultRollback(false);
		return (ConfigurableApplicationContext) ContainerFactory.newInstance((String) key, getResources());
	}
    
    /**
     * get resources
     * 可以被子类覆盖
     * @return String[]
     */
	protected String[] getResources() {
		return new String[] {
				"classpath:framework/framework-persistence-hibernate.xml",
				"classpath:biz/biz-bookstore.xml" };
	}
	
}

然后再继承这个抽象类,代码如下:
public class CustomerDAOTest extends AbstractDaoTestCase {
	private CustomerDAO customerDAO;
	
	public void testCRUD() {
		Customer customer = new Customer();
//		customer.setId(1);
		customer.setLoginid("netfly");
		customer.setName("netfly");
		customer.setPasswd("1234");
		customer.setEmail("oo@oo.com");
		customer.setAddress("shanghai");
		customer.setStatus("1");
		
		//保存对象,这里总会把数据插入数据库
		customerDAO.save(customer);
//		// 保证id生成
		assertNotNull(customer.getId());
//
//		//重新获得对象
		customer = customerDAO.get(customer.getId());
		//保证能获取刚才保存的对象
		assertNotNull(customer);
		// 保证获取对象的属性值与保存时相同
		assertEquals("oo@oo.com", customer.getEmail());
		
//		// 删除对象
//		customerDAO.remove(customer);
//		try {
//			customerDAO.get(customer.getId());
//			fail("Entity found in database after deleted");
//		} catch (Exception e) {
//			assertNotNull(e.getMessage());
//		}	
                  //这里回滚没有任何效果
//		transactionManager.rollback(transactionStatus);
	}

	/**
	 * @param customerDAO the customerDAO to set
	 */
	public void setCustomerDAO(CustomerDAO customerDAO) {
		this.customerDAO = customerDAO;
	}
}
11 楼 daquan198163 2006-12-25  
不过这里面也有些陷阱:如果你的测试还是会把数据写入了数据库的话,可能是由于你加载的spring配置文件里有多个事务管理器或session工厂,从而导致AbstractTransactionalDataSourceSpringContextTests没有获得正确的TransactionManager或SessionFactory,所以就没能回滚
不过这种错误也不太容易犯,因为AbstractTransactionalDataSourceSpringContextTests默认按类型组装,如果她发现有多个TransactionManager类型的bean是要报错的,此时你需要调用setAutowireMode(this.AUTOWIRE_BY_NAME);使其按名称组装
10 楼 daquan198163 2006-12-25  
netfly 写道
daquan198163 写道
并且在测试结束后也可以回滚,免得污染DB
当然,像你那样在tearDown里面显式的flush也应该可以的


怎么回滚?我怎么回滚都不起作用,做插入操作的时候,总是把数据写入了数据库中。

你的ut不是已经扩展自AbstractTransactionalDataSourceSpringContextTests了吗,只要你不调用super.setDefaultRollback(false);这个基类默认就会回滚的呀!
于是由此产生hibernate偷懒,无法发现数据库操作错误的问题了,然后我们建议你在测试中显示调用session.flush
或者参杂一些查询调用(其实也是为了触发session.flush)
9 楼 Godlikeme 2006-12-25  
netfly 写道
daquan198163 写道
并且在测试结束后也可以回滚,免得污染DB
当然,像你那样在tearDown里面显式的flush也应该可以的


怎么回滚?我怎么回滚都不起作用,做插入操作的时候,总是把数据写入了数据库中。
这个问题太模糊了,不如把代码贴出来,大家看个清楚,
8 楼 netfly 2006-12-25  
daquan198163 写道
并且在测试结束后也可以回滚,免得污染DB
当然,像你那样在tearDown里面显式的flush也应该可以的


怎么回滚?我怎么回滚都不起作用,做插入操作的时候,总是把数据写入了数据库中。
7 楼 daquan198163 2006-12-25  
Godlikeme 写道
daquan198163 写道
ecsun 写道
super.setDefaultRollBack(false)

请先看清楚问题
执行查询的时候是session flush 的,参考hibernate3.1文档10.10. Flushing the Session

对呀,这样不就可以防止hibernate不干活了么?并且在测试结束后也可以回滚,免得污染DB
当然,像你那样在tearDown里面显式的flush也应该可以的
6 楼 Godlikeme 2006-12-24  
daquan198163 写道
ecsun 写道
super.setDefaultRollBack(false)

请先看清楚问题
执行查询的时候是session flush 的,参考hibernate3.1文档10.10. Flushing the Session
5 楼 daquan198163 2006-12-24  
ecsun 写道
super.setDefaultRollBack(false)

请先看清楚问题
4 楼 daquan198163 2006-12-24  
好象遇到过类似问题,发现在调用一些查询方法后,之前还正常的一些测试会报错,当时觉得很奇怪。
楼主你试试在代码中掺杂一些无关紧要的查询方法调用,估计hibernate怕你读出脏数据就会执行写入操作了
3 楼 netfly 2006-12-24  
用super.setDefaultRollBack(false)我试过,弄脏了数据。
Godlikeme的方法我再尝试一下,多谢各位的帮助。
2 楼 Godlikeme 2006-12-24  
这个问题的关键在于,AbstractTransactionalDataSourceSpringContextTests缺乏对hibernate session的处理,需要对其进行扩展,
不知道测试代码是怎么写的,只是很奇怪没有session支持,测试怎么跑的起来。
扩展基本思路是在事务开始后,结束前把测试方法包装在

HibernateTemaplate.executeWithSession(...){
public Object doInHibernate(Session session) {
runTest();
session.flush();//synchornize database, errors will be reported.
session.clear();}...}

这样在事务提交或回滚前,错误会报出来。




1 楼 Godlikeme 2006-12-24  
不好意思,刚才问题没想清楚,代我再想想发出来。

相关推荐

Global site tag (gtag.js) - Google Analytics