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); }
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测试中会被最先调用,并且只会调用一次。 */@BeforeClasspublic static void init() throws DatabaseUnitException{//System.out.println("BEFOREclass init");MyLog4jLogger.debug("AbstractDbUnitTestCase init() BeforeClass");//在测试运行之前,便给dbunitCon初始化并赋值。dbunitCon=new DatabaseConnection(DbUtil.getCon());}/** * 测试完成之后,此方法便会被运行,关闭dbunitCon */@AfterClasspublic 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是没有权限修改的。 */@Deprecatedprotected 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);}}
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{@Injectprivate IUserDao userDao;@Injectprivate SessionFactory sessionFactory;@Beforepublic 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); }@Testpublic void testUser(){//test code}@Afterpublic void tearDown() throws FileNotFoundException, DatabaseUnitException, SQLException{//teardown code this.resumeTable();}}