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

基于Spring的单元测试框架搭建及分布式数据源单元测试

阅读更多

 

在Space 1st Apps的项目中,我们使用了基于Spring的单元测试 ,  并结合DBUnit对数据库应用程序做单元测试。

其中,数据源我们使用了Oracle、MySql数据库,Oracle数据源只有一个数据库,而MySQL数据源是一个由多台MySQL数据库组成的分布式多数据源。

 

对于单数据源Single DataSource的单元测试用例,如果你需要在测试用例运行之前准备一些种子数据,那么,你只需要简单地继承抽象类:AbstractDataSourceTest,例如:

@ContextConfiguration(locations = { "/spring/space-apps-poke.xml" })
public class PokeInfoManagerTest extends AbstractDataSourceTest {
    ……
	@Override
	protected String getSeedXmlFile() {
		return "/seeds/poke/pokeinfo.xml";
	}
    ……
}

 

其中,@ContextConfiguration的参数locations的值,表示类路径下的Spring配置文件的位置,例如:/spring/space-apps-poke.xml,在开发时,你将该文件放在了src/conf文件下面,将该文件夹作为源文件夹使用,这样该文件夹下面的所有文件,就都会在类路径下面了,如下图所示:



必须实现的抽象方法:

protected abstract String getSeedXmlFile()

该方法实现,需要你返回类路径下面的测试种子数据XML文件的位置,测试种子数据文件统一放到src/conf.test下面,如下图所示:



 在测试用例中,如果需要引用Spring的bean,只需像下面代码这样:

……
@Autowired
private PokeInfoManager pokeInfoManager;
……
 

 一旦加上了@Autowired注解之后,id为“pokeInfoManager“的bean,就会自动注入到测试用例中。

 测试方法,只需在普通的方法前面加上注解@Test,就可以被单元测试框架运行,例如:

 

	@Test
	public void getAllPokeInfoNotCached() {
		memCachedTemplate.delete(AppsKeyAccessor.Memcached.SPACE_APPS_POKE);
		List<PokeInfo> pokeInfoList = pokeInfoManager.getAllPokeInfo();
		assertNotNull(pokeInfoList);
		assertTrue(!pokeInfoList.isEmpty());
	}
   

 

附上抽象超类的源码

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class,
		DirtiesContextTestExecutionListener.class })
@ContextConfiguration(locations = { "/spring/space-memcached.xml",
		"/spring/space-datasource.xml", "/spring/space-commons.xml",
		"/spring/space-datasource-multi.xml" })
public abstract class AbstractDataSourceTest {

	private Resource resource;
	private IDatabaseTester tester;
	@Autowired
	@Qualifier("spaceOracleDS")
	private DataSource dataSource;

	/**
	 * Returns the test data seeds file in XML format
	 */
	protected abstract String getSeedXmlFile();

	/**
	 * Creates a new IDatabaseTester.<br>
	 * Default implementation returns a {@link DataSourceDatabaseTester}
	 * configured with the value returned from {@link getDataSource()}.
	 */
	protected IDatabaseTester newDatabaseTester() {
		return new DataSourceDatabaseTester(getDataSource());
	}

	/**
	 *Returns the test DataSource.
	 */
	protected DataSource getDataSource() {
		return this.dataSource;
	}

	/**
	 * Gets the IDatabaseTester for this testCase.<br>
	 * If the IDatabaseTester is not set yet, this method calls
	 * newDatabaseTester() to obtain a new instance.
	 * 
	 * @throws Exception
	 */
	protected IDatabaseTester getDatabaseTester() throws Exception {
		if (this.tester == null) {
			this.tester = newDatabaseTester();
		}
		return this.tester;
	}

	/**
	 * Returns the database operation executed in test setup. default is
	 * DatabaseOperation.REFRESH
	 */
	protected DatabaseOperation getSetUpOperation() throws Exception {
		return DatabaseOperation.REFRESH;
	}

	/**
	 * Returns the database operation executed in test cleanup.default is
	 * DatabaseOperation.NONE
	 */
	protected DatabaseOperation getTearDownOperation() throws Exception {
		return DatabaseOperation.NONE;
	}

	/**
	 * Returns data set resource in spring resource mode. eg: /seeds/xxx.xml If
	 * the Resource is not set yet, this method calls newDataSetResource() to
	 * obtain a new instance.
	 */
	private Resource getDataSetResource() {
		if (this.resource == null) {
			this.resource = newDataSetResource();
		}
		return this.resource;
	}

	/**
	 * Creates a new Resource.<br>
	 * Default implementation returns a {@link ClassPathResource} configured
	 * with the value returned from {@link getSeedXmlFile()}.
	 */
	protected Resource newDataSetResource() {
		return new ClassPathResource(getSeedXmlFile());
	}

	/**
	 * Returns the test dataset. default is FlatXmlDataSet
	 */
	private IDataSet getDataSet() throws Exception {
		return new FlatXmlDataSet(getDataSetResource().getInputStream());
	}

	@Before
	public void setUp() throws Exception {
		final IDatabaseTester databaseTester = getDatabaseTester();
		databaseTester.setSetUpOperation(getSetUpOperation());
		databaseTester.setDataSet(getDataSet());
		databaseTester.onSetup();
	}

	@After
	public void tearDown() throws Exception {
		final IDatabaseTester databaseTester = getDatabaseTester();
		databaseTester.setTearDownOperation(getTearDownOperation());
		databaseTester.setDataSet(getDataSet());
		databaseTester.onTearDown();
		tester = null;
	}
}
 

 

如果你不需要测试种子数据,请不要继承AbstractDataSourceTest类,而是仅需继承Spring 测试框架自带的类:AbstractJUnit4SpringContextTests

 

如果你的测试用例想使用事务,譬如说,你不想每次运行测试用例,都把数据真实地插入到数据库中,你可以使用事务的自动回滚机制,这很简单,你只需要继承AbstractTransactionalDataSourceTest

@ContextConfiguration(locations = { "/spring/space-apps-album.xml" })
public class BoPhotoManagerTest extends AbstractTransactionalDataSourceTest {

    ……
	@Override
	protected String getSeedXmlFile() {
		return "/seeds/admin/bophoto/bophoto.xml";
	}
    ……
}
 

 以上代码和无事务支持,需要测试种子数据测试用例比较类似,在此,不再累赘。

 

 附上AbstractTransactionalDataSourceTest的源代码:

@TestExecutionListeners( { TransactionalTestExecutionListener.class })
@Transactional
@TransactionConfiguration(transactionManager = "jtaTransactionManager")
public abstract class AbstractTransactionalDataSourceTest extends
		AbstractDataSourceTest {
}
 

其中,注解@TransactionConfiguration的参数transactionManager的值为jtaTransactionManager,是Spring的bean的Id

 

如果测试用例需要多数据源分布式数据库,大致类似,简单说一下

 

对于需要测试种子数据的,请继承AbstractDistributedDataSourceTest,附上该类源码:

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class,
		DirtiesContextTestExecutionListener.class })
@ContextConfiguration(locations = { "/spring/space-memcached.xml",
		"/spring/space-datasource.xml", "/spring/space-commons.xml",
		"/spring/space-datasource-multi.xml" })
public abstract class AbstractDistributedDataSourceTest {

	private Resource resource;
	private IDistributedDatabaseTester tester;
	@Autowired
	@Qualifier("distributeDBDataSource")
	private DataSource dataSource;

	/**
	 * Returns the test data seeds file in XML format
	 */
	protected abstract String getSeedXmlFile();

	/**
	 * Creates a new IDistributedDatabaseTester.<br>
	 * Default implementation returns a
	 * {@link DistributedDataSourceDatabaseTester} configured with the value
	 * returned from {@link getDataSource()}.
	 */
	protected IDistributedDatabaseTester newDatabaseTester() {
		return new DistributedDataSourceDatabaseTester(getDataSource());
	}

	/**
	 *Returns the test DataSource.
	 */
	protected DataSource getDataSource() {
		return this.dataSource;
	}

	/**
	 * Gets the IDatabaseTester for this testCase.<br>
	 * If the IDatabaseTester is not set yet, this method calls
	 * newDatabaseTester() to obtain a new instance.
	 * 
	 * @throws Exception
	 */
	protected IDistributedDatabaseTester getDatabaseTester() throws Exception {
		if (this.tester == null) {
			this.tester = newDatabaseTester();
		}
		return this.tester;
	}

	/**
	 * Returns the database operation executed in test setup. default is
	 * DatabaseOperation.REFRESH
	 */
	protected DistributedDatabaseOperation getSetUpOperation() throws Exception {
		return DistributedDatabaseOperation.REFRESH;
	}

	/**
	 * Returns the database operation executed in test cleanup.default is
	 * DatabaseOperation.NONE
	 */
	protected DistributedDatabaseOperation getTearDownOperation()
			throws Exception {
		return DistributedDatabaseOperation.NONE;
	}

	/**
	 * Returns data set resource in spring resource mode. eg: /seeds/xxx.xml If
	 * the Resource is not set yet, this method calls newDataSetResource() to
	 * obtain a new instance.
	 */
	private Resource getDataSetResource() {
		if (this.resource == null) {
			this.resource = newDataSetResource();
		}
		return this.resource;
	}

	/**
	 * Creates a new Resource.<br>
	 * Default implementation returns a {@link ClassPathResource} configured
	 * with the value returned from {@link getSeedXmlFile()}.
	 */
	protected Resource newDataSetResource() {
		return new ClassPathResource(getSeedXmlFile());
	}

	/**
	 * Returns the test dataset. default is FlatXmlDataSet
	 */
	private IExtDataSet getDataSet() throws Exception {
		return new ExtXmlDataSet(getDataSetResource().getInputStream());
	}

	@Before
	public void setUp() throws Exception {
		final IDistributedDatabaseTester databaseTester = getDatabaseTester();
		databaseTester.setSetUpOperation(getSetUpOperation());
		databaseTester.setDataSet(getDataSet());
		databaseTester.onSetup();
	}

	@After
	public void tearDown() throws Exception {
		final IDistributedDatabaseTester databaseTester = getDatabaseTester();
		databaseTester.setTearDownOperation(getTearDownOperation());
		databaseTester.setDataSet(getDataSet());
		databaseTester.onTearDown();
		tester = null;
	}
}
   

 如果需要事务回滚机制,请继承AbstractTransactionalDistributedDataSourceTest,附上该类源码

@TestExecutionListeners( { TransactionalTestExecutionListener.class })
@Transactional
@TransactionConfiguration(transactionManager = "jtaTransactionManager")
public abstract class AbstractTransactionalDistributedDataSourceTest extends
		AbstractDistributedDataSourceTest {

}
 

 

好了,到目前为止,测试用例是写好了,但是测试种子数据,还没有准备,这个XML文件,看起来还蛮复杂的,大家看一下样本,

<?xml version='1.0' encoding='UTF-8'?>
<dataset>
	<FA_POKE_INFO POKEINFO_ID="01" POKE_NAME="微笑" POKE_IMG_PATH="/poke/poke_01.gif" POKE_TEMPLATE_CONTENT="{0}对{1}亲切地微笑了一下"
		GMT_CREATE="2009-06-09 12:53:43.0" GMT_MODIFIED="2009-06-09 12:53:43.0" CREATOR="sns" MODIFIER="sns" IS_DELETED="n" />
	<FA_POKE_INFO POKEINFO_ID="02" POKE_NAME="轻轻地碰" POKE_IMG_PATH="/poke/poke_02.gif" POKE_TEMPLATE_CONTENT="{0}轻轻地碰了{1}一下"
		GMT_CREATE="2009-06-09 12:53:43.0" GMT_MODIFIED="2009-06-09 12:53:43.0" CREATOR="sns" MODIFIER="sns" IS_DELETED="n" />
	<FA_POKE_INFO POKEINFO_ID="03" POKE_NAME="握手" POKE_IMG_PATH="/poke/poke_03.gif" POKE_TEMPLATE_CONTENT="{0}和{1}握了一下手"
		GMT_CREATE="2009-06-09 12:53:43.0" GMT_MODIFIED="2009-06-09 12:53:43.0" CREATOR="sns" MODIFIER="sns" IS_DELETED="n" />
	<FA_POKE_INFO POKEINFO_ID="04" POKE_NAME="依偎" POKE_IMG_PATH="/poke/poke_04.gif" POKE_TEMPLATE_CONTENT="{0}和{1}紧紧依偎在一起"
		GMT_CREATE="2009-06-09 12:53:43.0" GMT_MODIFIED="2009-06-09 12:53:43.0" CREATOR="sns" MODIFIER="sns" IS_DELETED="n" />
	<FA_POKE_INFO POKEINFO_ID="05" POKE_NAME="深情地飞吻" POKE_IMG_PATH="/poke/poke_05.gif" POKE_TEMPLATE_CONTENT="{0}深情地飞吻了{1}一下"
		GMT_CREATE="2009-06-09 12:53:43.0" GMT_MODIFIED="2009-06-09 12:53:43.0" CREATOR="sns" MODIFIER="sns" IS_DELETED="n" />
	<FA_POKE_INFO POKEINFO_ID="06" POKE_NAME="小心地捏" POKE_IMG_PATH="/poke/poke_06.gif" POKE_TEMPLATE_CONTENT="{0}小心地捏了{1}一下"
		GMT_CREATE="2009-06-09 12:53:43.0" GMT_MODIFIED="2009-06-09 12:53:43.0" CREATOR="sns" MODIFIER="sns" IS_DELETED="n" />
	<FA_POKE_INFO POKEINFO_ID="07" POKE_NAME="重重地扁" POKE_IMG_PATH="/poke/poke_07.gif" POKE_TEMPLATE_CONTENT="{0}把{1}重重地扁了一顿"
		GMT_CREATE="2009-06-09 12:53:43.0" GMT_MODIFIED="2009-06-09 12:53:43.0" CREATOR="sns" MODIFIER="sns" IS_DELETED="n" />
	……
</dataset>

 

以上XML片段是一个样本,根节点是dataset,每个子节点表示表的名称,如FA_POKE_INFO,每个节点的属性如POKE_INFO_ID,表示数据库表的列名,每个节点的属性的值就是数据表对应列的值

 

OK,从头开始写这么一个文件,我觉得你一定会没有耐心,还是有一些工作量的。

 

还好,我写了几个工具类,你只需要简单地修改几个参数, 然后运行一下,上述的XML代码就会生成了,好,我们来看代码说话,由于我们使用了Oracle和MySQL数据库,所以我使用了模板方法模式,做了少许抽象,DatabaseExporter源码:

public abstract class DatabaseExporter {

	private IDatabaseConnection databaseConnection;
	private Connection jdbcConnection;

	/**
	 * write DTD file
	 * 
	 * @param dtdFileName
	 * 
	 * @throws Exception
	 */
	protected void writeDataDtd(String dtdFileName) throws Exception {
		IDataSet dataSet = getDatabaseConnection().createDataSet();
		Writer out = new OutputStreamWriter(new FileOutputStream(dtdFileName));
		FlatDtdWriter datasetWriter = new FlatDtdWriter(out);
		datasetWriter.setContentModel(FlatDtdWriter.CHOICE);
		datasetWriter.write(dataSet);
	}

	private IDatabaseConnection getDatabaseConnection() throws Exception {
		if (this.databaseConnection == null) {
			this.databaseConnection = newDatabaseConnection(getJdbcConnection());
		}
		return this.databaseConnection;
	}

	private Connection getJdbcConnection() throws Exception {
		if (this.jdbcConnection == null) {
			this.jdbcConnection = newJdbcConnection();
		}
		return this.jdbcConnection;
	}

	/**
	 * full database export
	 * 
	 * @param fullXmlFileName
	 * @param isFlatXml
	 * 
	 * @throws Exception
	 */
	protected void exportFullDataSet(String fullXmlFileName, boolean isFlatXml)
			throws Exception {
		IDataSet fullDataSet = getDatabaseConnection().createDataSet();
		if (isFlatXml) {
			FlatXmlDataSet.write(fullDataSet, new FileOutputStream(
					fullXmlFileName));
		} else {
			XmlDataSet
					.write(fullDataSet, new FileOutputStream(fullXmlFileName));
		}
	}

	/**
	 * dependent tables database export: export table X and all tables that have
	 * a PK which is a FK on X, in the right order for insertion
	 * 
	 * @param rootTableName
	 * @param dependentXmlFileName
	 * @param isFlatXml
	 * @throws Exception
	 */
	protected void exportDependentDataSet(String rootTableName,
			String dependentXmlFileName, boolean isFlatXml) throws Exception {
		String[] depTableNames = TablesDependencyHelper.getAllDependentTables(
				getDatabaseConnection(), rootTableName);
		IDataSet depDataset = getDatabaseConnection().createDataSet(
				depTableNames);
		if (isFlatXml) {
			FlatXmlDataSet.write(depDataset, new FileOutputStream(
					dependentXmlFileName));
		} else {
			XmlDataSet.write(depDataset, new FileOutputStream(
					dependentXmlFileName));
		}
	}

	/**
	 * partial database export
	 * 
	 * @param tableName
	 * @param partialXmlFileName
	 * @param isFlatXml
	 * @throws Exception
	 */
	protected void exportPartialDataSet(String tableName,
			String partialXmlFileName, boolean isFlatXml) throws Exception {
		QueryDataSet partialDataSet = new QueryDataSet(getDatabaseConnection());
		partialDataSet.addTable(tableName);
		if (isFlatXml) {
			FlatXmlDataSet.write(partialDataSet, new FileOutputStream(
					partialXmlFileName));
		} else {
			XmlDataSet.write(partialDataSet, new FileOutputStream(
					partialXmlFileName));
		}
	}

	/**
	 * partial multiple database export
	 * 
	 * @param tableName2Query
	 * @param partialXmlFileName
	 * @param isFlatXml
	 * @throws Exception
	 */
	protected void exportMultiPartialDataSet(
			Map<String, String> tableName2Query, String partialXmlFileName,
			boolean isFlatXml) throws Exception {
		QueryDataSet partialDataSet = new QueryDataSet(getDatabaseConnection());
		Validate.notEmpty(tableName2Query,
				"Please check tableName2Query, it must not be null or empty");
		Map<String, String> treeMap = new TreeMap<String, String>(
				tableName2Query);
		Set<Map.Entry<String, String>> entrys = treeMap.entrySet();
		for (Entry<String, String> entry : entrys) {
			if (StringUtils.isBlank(entry.getValue())) {
				partialDataSet.addTable(entry.getKey());
			} else {
				partialDataSet.addTable(entry.getKey(), entry.getValue());
			}
		}

		if (isFlatXml) {
			FlatXmlDataSet.write(partialDataSet, new FileOutputStream(
					partialXmlFileName));
		} else {
			XmlDataSet.write(partialDataSet, new FileOutputStream(
					partialXmlFileName));
		}

	}

	/**
	 * partial database export
	 * 
	 * @param tableName
	 * @param query
	 * @param isFlatXml
	 * @throws Exception
	 */
	protected void exportPartialDataSet(String tableName, String query,
			String partialXmlFileName, boolean isFlatXml) throws Exception {
		QueryDataSet partialDataSet = new QueryDataSet(getDatabaseConnection());
		partialDataSet.addTable(tableName, query);
		if (isFlatXml) {
			FlatXmlDataSet.write(partialDataSet, new FileOutputStream(
					partialXmlFileName));
		} else {
			XmlDataSet.write(partialDataSet, new FileOutputStream(
					partialXmlFileName));
		}
	}

	protected abstract Connection newJdbcConnection() throws Exception;

	protected abstract IDatabaseConnection newDatabaseConnection(
			Connection jdbcConnection);

}
 

 MySQL 数据导出工具源代码:

public class MysqlDatabaseExporter extends DatabaseExporter {

	@Override
	protected IDatabaseConnection newDatabaseConnection(
			Connection jdbcConnection) {
		return new MySqlConnection(jdbcConnection, null);
	}

	@Override
	protected Connection newJdbcConnection() throws Exception {
		Class.forName("com.mysql.jdbc.Driver");
		return DriverManager.getConnection(
				"jdbc:mysql://10.2.225.151:3306/SNS", "sns", "alisoft");
	}

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		MysqlDatabaseExporter exporter = new MysqlDatabaseExporter();
		Map<String, String> map = new HashMap<String, String>();
		map.put("FA_GIFT_RECEIVER",
				"SELECT * FROM SNS.FA_GIFT_RECEIVER F limit 0,10;");
		map.put("FA_GIFT_SENDER",
				"SELECT * FROM SNS.FA_GIFT_SENDER F limit 0,10;");
		map.put("FA_GIFT_STAT", "SELECT * FROM SNS.FA_GIFT_STAT F limit 0,10;");
		exporter.exportMultiPartialDataSet(map, "statefullGift.xml", false);
		// exporter.writeDataDtd("myFile.dtd");
		// exporter.exportFullDataSet("full.xml", false);
		// exporter.exportDependentDataSet("FA_PHOTO", "dependents.xml", false);
	}
}
 

 Oracle 数据导出工具源代码:

public class OracleDatabaseExporter extends DatabaseExporter {

	@Override
	protected IDatabaseConnection newDatabaseConnection(
			Connection jdbcConnection) {
		OracleConnection connection = new OracleConnection(jdbcConnection, null);
		connection.getConfig().setFeature(
				DatabaseConfig.FEATURE_SKIP_ORACLE_RECYCLEBIN_TABLES, true);
		return connection;
	}

	@Override
	protected Connection newJdbcConnection() throws Exception {
		Class.forName("oracle.jdbc.driver.OracleDriver");
		return DriverManager.getConnection(
				"jdbc:oracle:thin:@10.2.224.34:1521:aepdb", "sns", "sns");
	}

	/**
	 * @param args
	 * @throws Exception
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		OracleDatabaseExporter exporter = new OracleDatabaseExporter();
		exporter.exportPartialDataSet("FA_POKE_INFO", "partial.xml", false);
		exporter.writeDataDtd("myFile.dtd");
		// exporter.exportFullDataSet("full.xml", false);
		exporter.exportDependentDataSet("BO_PHOTO", "dependents.xml", false);
	}
}
   

代码很简单,如果你熟悉DBUnit,大家一看就会明白,我主要说说怎么个用法,对了,有一个小插曲,我们的多数据源分布式数据库,是根据用户的longId进行取模,然后选择不同的数据库的,这样为多数据源分布式数据库准备单元测试的种子数据,就会产生很大的障碍,我们必须能够让种子数据自动选择他们应该归属的数据库。

 

DBUnit的测试种子数据,大家使用最多的应该是FlatXMLFile,如上面的测试种子数据例子

 

在插入测试种子数据时,我们无法知道XML节点的哪个字段是作为选择多数据源的字段,我们使用isResourceId表示,平行化的结构很难表达这个ResourceId的意思。还好,DBUnit有一种非平行化的XML结构,如下XML代码所示:

<?xml version='1.0' encoding='UTF-8'?>
<dataset>
	<table name="FA_POKE">
		<column>POKE_ID</column>
		<column>SENDER_LONG_ID</column>
		<column isResourceId="true">RECEIVER_LONG_ID</column>
		<column>POKE_CONTENT</column>
		<column>GMT_CREATE</column>
		<column>GMT_MODIFIED</column>
		<column>IS_DELETED</column>
	</table>
</dataset>
   

以上XML片段中,dataset表示根节点,table表示一个表,name属性表示table的名称,column表示table的一个列,中间的文本表示列名。

像以上这样,我们就可以在某个数据列上面表示哪个是ResoutceId,如上面例子中:isResourceId="true"的列,RECEIVIER_LONG_I,当然,默认的DBUnit是不支持这种扩展的,为了这个扩展,我费了很多的力气,感觉DBUnit的扩展性不是很好,至于扩展的代码,有很多,这里就不一一列举了。

 

说说上面的Exporter的使用方法,为了导出数据库中某个表,使用:

protected void exportPartialDataSet(String tableName,
            String partialXmlFileName, boolean isFlatXml)
protected void exportPartialDataSet(String tableName, String query,
			String partialXmlFileName, boolean isFlatXml) throws Exception
  • tableName,表示你要导出数据库的表名
  • query,表示针对tableName的一个select查询语句,如:"select * from tableName limit 0, 1000"
  • partialXmlFileName,表示导出的XML种子数据的文件名称
  • isFlatXml,表示导出的XML文件是否是Flat结构,true,表示Flat XML,false表示树状XML

 

为了导出数据库中的多个表数据到一个XML文件中,使用:

protected void exportMultiPartialDataSet(
			Map<String, String> tableName2Query, String partialXmlFileName,
			boolean isFlatXml) throws Exception
 
  • tableName2Query,表示tableName到query语句的map,key为tableName,value为query语句,可以为空
  • partialXmlFileName,表示导出的XML种子数据的文件名称
  • isFlatXml,表示导出的XML文件是否是Flat结构,true,表示Flat XML,false表示树状XML

另外,还有两个方法,其一:

protected void exportFullDataSet(String fullXmlFileName, boolean isFlatXml)
			throws Exception
 

该方法用于导出数据库中所有表到一个XML文件中,一般情况下,不需要使用该方法,尤其是数据量很大的时候,参数定义如下:

  • fullXmlFileName,表示导出的XML种子数据的文件名称
  • isFlatXml,表示导出的文件是否是Flat结构,true,表示Flat XML,false表示树状XML

其二:

protected void writeDataDtd(String dtdFileName) throws Exception

该方法用于导出数据库表结构到一个DTD文件中,注意:该方法,可能对Oracle 10i 以上开启回收站功能的数据库,运行会失败,解决方案,就是禁用这个功能,需要DBA支持,遇到该问题时,你可以Google一下。

 

好了,说了这么多了,希望对你有用

  • 大小: 30 KB
  • 大小: 12.7 KB
1
0
分享到:
评论
1 楼 CoderDream 2009-07-30  
不错,感谢分享!

相关推荐

    ysoserial-master.zip

    ysoserial是一个用于生成利用不安全的Java对象反序列化的有效负载的概念验证工具。它包含一系列在常见Java库中发现的"gadget chains",可以在特定条件下利用执行不安全的反序列化操作的Java应用程序。ysoserial项目最初在2015年AppSecCali会议上提出,包含针对Apache Commons Collections(3.x和4.x版本)、Spring Beans/Core(4.x版本)和Groovy(2.3.x版本)的利用链

    zigbee CC2530无线自组网协议栈系统代码实现协调器与终端的TI Sensor实验和Monitor使用.zip

    1、嵌入式物联网单片机项目开发例程,简单、方便、好用,节省开发时间。 2、代码使用IAR软件开发,当前在CC2530上运行,如果是其他型号芯片,请自行移植。 3、软件下载时,请注意接上硬件,并确认烧录器连接正常。 4、有偿指导v:wulianjishu666; 5、如果接入其他传感器,请查看账号发布的其他资料。 6、单片机与模块的接线,在代码当中均有定义,请自行对照。 7、若硬件有差异,请根据自身情况调整代码,程序仅供参考学习。 8、代码有注释说明,请耐心阅读。 9、例程具有一定专业性,非专业人士请谨慎操作。

    YOLO算法-自卸卡车-挖掘机-轮式装载机数据集-2644张图像带标签-自卸卡车-挖掘机-轮式装载机.zip

    YOLO系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中,文件名末尾是部分类别名称; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值; 【注】可以下拉页面,在资源详情处查看标签具体内容;

    Oracle10gDBA学习手册中文PDF清晰版最新版本

    **Oracle 10g DBA学习手册:安装Oracle和构建数据库** **目的:** 本章节旨在指导您完成Oracle数据库软件的安装和数据库的创建。您将通过Oracle Universal Installer (OUI)了解软件安装过程,并学习如何利用Database Configuration Assistant (DBCA)创建附加数据库。 **主题概览:** 1. 利用Oracle Universal Installer (OUI)安装软件 2. 利用Database Configuration Assistant (DBCA)创建数据库 **第2章:Oracle软件的安装与数据库构建** **Oracle Universal Installer (OUI)的运用:** Oracle Universal Installer (OUI)是一个图形用户界面(GUI)工具,它允许您查看、安装和卸载机器上的Oracle软件。通过OUI,您可以轻松地管理Oracle软件的安装和维护。 **安装步骤:** 以下是使用OUI安装Oracle软件并创建数据库的具体步骤:

    消防验收过程服务--现场记录表.doc

    消防验收过程服务--现场记录表.doc

    (4655036)数据库 管理与应用 期末考试题 数据库试题

    数据库管理\09-10年第1学期数据库期末考试试卷A(改卷参考).doc。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。

    YOLO算法-瓶纸盒合并数据集-3161张图像带标签-纸张-纸箱-瓶子.zip

    YOLO系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中,文件名末尾是部分类别名称; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值; 【注】可以下拉页面,在资源详情处查看标签具体内容;

    职业暴露后的处理流程.docx

    职业暴露后的处理流程.docx

    Java Web开发短消息系统

    Java Web开发短消息系统

    java毕设项目之ssm基于java和mysql的多角色学生管理系统+jsp(完整前后端+说明文档+mysql+lw).zip

    项目包含完整前后端源码和数据库文件 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/idea Maven包:Maven3.3 服务器:tomcat7

    批量导出多项目核心目录工具

    这是一款可以配置过滤目录及过滤的文件后缀的工具,并且支持多个项目同时输出导出,并过滤指定不需要导出的目录及文件后缀。 导出后将会保留原有的路径,并在新的文件夹中体现。

    【图像压缩】基于matlab GUI DCT图像压缩(含MAX MED MIN NONE)【含Matlab源码 9946期】.zip

    Matlab领域上传的视频均有对应的完整代码,皆可运行,亲测可用,适合小白; 1、代码压缩包内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作

    YOLO算法-挖掘机与火焰数据集-7735张图像带标签-挖掘机.zip

    YOLO算法-挖掘机与火焰数据集-7735张图像带标签-挖掘机.zip

    操作系统实验 Ucore lab5

    操作系统实验 Ucore lab5

    IMG_5950.jpg

    IMG_5950.jpg

    竞选报价评分表.docx

    竞选报价评分表.docx

    java系统,mysql、springboot等框架

    java系统,mysql、springboot等框架

    zigbee CC2530网关+4节点无线通讯实现温湿度、光敏、LED、继电器等传感节点数据的采集上传,网关通过ESP8266上传远程服务器及下发控制.zip

    1、嵌入式物联网单片机项目开发例程,简单、方便、好用,节省开发时间。 2、代码使用IAR软件开发,当前在CC2530上运行,如果是其他型号芯片,请自行移植。 3、软件下载时,请注意接上硬件,并确认烧录器连接正常。 4、有偿指导v:wulianjishu666; 5、如果接入其他传感器,请查看账号发布的其他资料。 6、单片机与模块的接线,在代码当中均有定义,请自行对照。 7、若硬件有差异,请根据自身情况调整代码,程序仅供参考学习。 8、代码有注释说明,请耐心阅读。 9、例程具有一定专业性,非专业人士请谨慎操作。

    YOLO算法-快递衣物数据集-496张图像带标签.zip

    YOLO系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中,文件名末尾是部分类别名称; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值; 【注】可以下拉页面,在资源详情处查看标签具体内容;

    搜索引擎lucen的相关介绍 从事搜索行业程序研发、人工智能、存储等技术人员和企业

    内容概要:本文详细讲解了搜索引擎的基础原理,特别是索引机制、优化 like 前缀模糊查询的方法、建立索引的标准以及针对中文的分词处理。文章进一步深入探讨了Lucene,包括它的使用场景、特性、框架结构、Maven引入方法,尤其是Analyzer及其TokenStream的实现细节,以及自定义Analyzer的具体步骤和示例代码。 适合人群:数据库管理员、后端开发者以及希望深入了解搜索引擎底层实现的技术人员。 使用场景及目标:适用于那些需要优化数据库查询性能、实施或改进搜索引擎技术的场景。主要目标在于提高数据库的访问效率,实现高效的数据检索。 阅读建议:由于文章涉及大量的技术术语和实现细节,建议在阅读过程中对照实际开发项目,结合示例代码进行实践操作,有助于更好地理解和吸收知识点。

Global site tag (gtag.js) - Google Analytics