dbunit入门 (二)数据的备份与恢复

这里讲如何将我们将要测试的数据库的表的数据进行备份,然后测试, 最后恢复数据库数据。


这里的核心过程就是
-> QueryDataSet获取数据库信息。
-> FlatXmlDataSet.write写入数据库数据到xml文件中。
-> 进行测试
-> 测试完成, 从xml文件恢复数据到数据库中

这里的几个核心的Dbunit类:

1. org.dbunit.dataset.IDataSet
这个接口是关于存放所有table信息的,包括xml文件的table数据信息以及数据库中读取到的table数据信息。

2. org.dbunit.dataset.xml.FlatXmlDataSet
这个类用于读写上面的IDataSet所存储的信息。
它可以从xml文件中读取信息,并写入到IDataSet中。
或者从IDataSet中读取信息,并写入到xml文件中。

3. org.dbunit.database.QueryDataSet
这个类保存所有根据sql语句查询到的表的内容。
它通过如下的构造函数获取IDatabaseConnection。
private final IDatabaseConnection _connection;
public QueryDataSet(IDatabaseConnection connection)。

这个类的核心方法是addTable(), 源码如下:
  /**
* Adds a table and it's associated query to this dataset.
*
* @param tableName The name of the table
* @param query The query to retrieve data with for this table. Can be null which will select
* all data (see {@link #addTable(String)} for details)
* @throws AmbiguousTableNameException
*/
public void addTable(String tableName, String query) throws AmbiguousTableNameException
{
logger.debug("addTable(tableName={}, query={}) - start", tableName, query);
_tables.add(tableName, new TableEntry(tableName, query));
}

/**
* Adds a table with using 'SELECT * FROM <code>tableName</code>' as query.
*
* @param tableName The name of the table
* @throws AmbiguousTableNameException
*/
public void addTable(String tableName) throws AmbiguousTableNameException
{
logger.debug("addTable(tableName={}) - start", tableName);
this.addTable(tableName, null);
}


它会将select语句和自己的OrderedTableNameMap对象绑定在一起。在后面需要查询数据库数据时, 便会执行SQL语句。(跟hibernate的session比较类似吧)。

================================================

[b]完整的AbstractDbUnitTestCase代码:[/b]

package com.lj.basic.test.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;

import junit.framework.Assert;

import org.dbunit.DatabaseUnitException;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.database.QueryDataSet;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.dataset.xml.FlatXmlProducer;
import org.dbunit.operation.DatabaseOperation;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.xml.sax.InputSource;

import com.lj.basic.test.util.AbstractDbUnitTestCase;
import com.lj.basic.test.util.DbUtil;
import com.lj.basic.util.MyLog4jLogger;


/**
* 此处我们使用lingling这个数据库schema来专门进行测试
* alleni用来存储我们的正式信息。
* lingling->在dbutil中配置的 -jdbc connection
* alleni-> 在beans.xml中配置的 -hibernate
* @author Administrator
*
*/
public class AbstractDbUnitTestCase {
public static IDatabaseConnection dbunitCon;


/**
* tempFile用来存放备份的数据信息<br/>
* 当测试数据时,会将数据信息存放到这个文件中。<br/>
* 测试完成之后,再将数据导回数据库。
*/
private File tempFile;

/**
* Beforeclass是在创建这个类之前所做的操作<br/>
* 这个方法必须为static<br/>
* 该方法在junit测试中会被最先调用,并且只会调用一次。
*/
@BeforeClass
public static void init() throws DatabaseUnitException{
//System.out.println("BEFOREclass init");
MyLog4jLogger.debug("AbstractDbUnitTestCase init() BeforeClass");
//在测试运行之前,便给dbunitCon初始化并赋值。
dbunitCon=new DatabaseConnection(DbUtil.getCon());
}

/**
* 测试完成之后,此方法便会被运行,关闭dbunitCon
*/
@AfterClass
public static void destory(){
try {
if(dbunitCon!=null)dbunitCon.close();

} catch (Exception e) {
e.printStackTrace();
}
MyLog4jLogger.debug("AbstractDbUnitTestCase destory() @AfterClass finished");
}

/**
* 通过项目中的xml文件获取测试数据<br/>
* @param table_name 数据表的名称
* @return 返回FlatXmlDataSet类型对象,包含了xml文件中的所有内容
*/
protected IDataSet createDataSet(String dataSource_name) throws DataSetException{

if(!dataSource_name.endsWith(".xml")){
dataSource_name+=".xml";
}
InputStream is=AbstractDbUnitTestCase.class.getClassLoader().getResourceAsStream(dataSource_name);

Assert.assertNotNull("dbunit的基本数据文件不存在", is);

return new FlatXmlDataSet(new FlatXmlProducer(new InputSource(is)));
}

/**
* 这个方法用于备份指定的几个表名
* @param tname 要备份的数据库中的表名称
*/
protected void backupCustomTable(String[] tname) throws DataSetException, IOException{
QueryDataSet backup=new QueryDataSet(dbunitCon);

for(String name:tname){
//这里将表名捆绑到QueryDataSet里面,这样在后面读取数据库的时候,就会产生对应的SQL语句。
backup.addTable(name);
}

//将IDataSet的数据信息写入tempFile中。
//里面调用了FlatXmlDataSet的write方法。
writeBackupFile(backup);
}


/**
* 将IDataSet的数据信息写入tempFile中。
* @param backupDataSet
*/
private void writeBackupFile(IDataSet ds) throws DataSetException, IOException{
if(tempFile==null||!tempFile.exists()){
tempFile = File.createTempFile("backup", ".xml");}
//System.out.println(tempFile.exists());
FlatXmlDataSet.write(ds, new FileWriter(tempFile));
}

/**
* 不建议在Oracle数据库中使用。因为dbunitCon.createDataSet()会获取oracle里面的各种表,其中很多jvm是没有权限修改的。
*/
@Deprecated
protected void backupAllTable() throws SQLException, DataSetException, IOException{
IDataSet ds=dbunitCon.createDataSet();
// System.out.println(ds.getTable("t_user").getRowCount());

// QueryDataSet qds=new QueryDataSet(dbunitCon);

writeBackupFile(ds);

}



protected void backupOneTable(String tname) throws DataSetException, IOException{
this.backupCustomTable(new String[]{tname});
}

/**
* 读取tempFile里的数据,从而恢复数据库原始的信息。
*/
protected void resumeTable() throws FileNotFoundException, DatabaseUnitException, SQLException{
IDataSet ds=new FlatXmlDataSet(new FlatXmlProducer(new InputSource(new FileInputStream(tempFile))));
DatabaseOperation.CLEAN_INSERT.execute(dbunitCon, ds);
}




}



当我们新建一个测试代码的时候, 只要让该代码继承AbstractDbUnitTestCase就行了。

简例如下:

package com.lj.core.dao;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;

import javax.inject.Inject;

import org.dbunit.DatabaseUnitException;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;
import org.dbunit.operation.DatabaseOperation;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.orm.hibernate4.SessionHolder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import com.lj.basic.test.util.AbstractDbUnitTestCase;


@RunWith(SpringJUnit4ClassRunner.class)
//这里的test_beans.xml中的数据库信息必须和dbutil中通过jdbc连接的数据库信息一致!
@ContextConfiguration("/test_beans.xml")//这里运行src/test/resources里面的test_beans.xml,该文件指定了lingling这个测试数据库对象
public class TestDbunit extends AbstractDbUnitTestCase
{
@Inject
private IUserDao userDao;


@Inject
private SessionFactory sessionFactory;

@Before
public void setUp() throws DatabaseUnitException, SQLException, IOException{
// Session s=sessionFactory.openSession();
// TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(s));
//
//这里的t_user就是t_user.xml,包含了我们要进行测试的信息
IDataSet ds=createDataSet("test_user");

//备份数据库信息,Oracle下不能使用该方法,要指定table名来备份
//this.backupAllTable();
this.backupOneTable("t_user");
//
DatabaseOperation.CLEAN_INSERT.execute(dbunitCon, ds);



}

@Test
public void testUser(){
//test code
}


@After
public void tearDown() throws FileNotFoundException, DatabaseUnitException, SQLException{
//teardown code
this.resumeTable();
}

}



============================================

最后还是要说, 这东西不熟练的情况下还是不要和运行数据库混淆。
测试就用测试的数据库, 网站运行就用运行的数据库。
虽然dbunit可以备份恢复数据, 但是一旦出了差错,还是非常麻烦的。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值