DBUnit最佳实践之数据备份与恢复

在做测试之前,我们需要对数据进行备份,用DBUnit可以很方便的对数据库中的数据进行备份和恢复。

 

目录结构

  • 项目结构图
  • 源代码
    1. 数据库工具类
    2. 导入导出类
    3. Maven工程文件
    4. 数据库配置属性文件
    5. 数据库脚本
    6. 日志配置文件
  • 参考文档
  • 完整项目源代码

项目结构图

源代码

数据库工具类

DBUtil.java

package com.coderdream;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ResourceBundle;

public class DBUtil {

	public static Connection getConnection() {
		Connection conn = null;
		try {
			ResourceBundle rs = ResourceBundle.getBundle("dbutil");

			Class.forName(rs.getString("db.classname"));
			conn = DriverManager.getConnection(rs.getString("db.url"), rs.getString("db.username"), rs.getString("db.password"));
		} catch (ClassNotFoundException e) {
			System.out.println("数据库驱动加载失败,堆栈轨迹如下");
			e.printStackTrace();
		} catch (SQLException e) {
			System.out.println("数据库连接创建失败,堆栈轨迹如下");
			e.printStackTrace();
		}
		return conn;
	}

	public static void closeAll(ResultSet rs, PreparedStatement pstmt, Connection conn) {
		if (null != rs) {
			try {
				rs.close();
			} catch (SQLException e) {
				System.out.println("数据库操作的ResultSet关闭失败,堆栈轨迹如下");
				e.printStackTrace();
			}
		}
		if (null != pstmt) {
			try {
				pstmt.close();
			} catch (SQLException e) {
				System.out.println("数据库操作的PreparedStatement关闭失败,堆栈轨迹如下");
				e.printStackTrace();
			}
		}
		close(conn);
	}

	public static void close(Connection conn) {
		if (null != conn) {
			try {
				conn.close();
				if (conn.isClosed()) {
					System.out.println("此数据库连接已关闭-->" + conn);
				} else {
					System.out.println("此数据库连接关闭失败-->" + conn);
				}
			} catch (SQLException e) {
				System.out.println("数据库连接关闭失败,堆栈轨迹如下");
				e.printStackTrace();
			}
		}
	}

}

导入导出类

DBExportImport.java

package com.coderdream;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.sql.Connection;
import java.sql.SQLException;

import org.dbunit.DatabaseUnitException;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.database.QueryDataSet;
import org.dbunit.dataset.CachedDataSet;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.csv.CsvDataSetWriter;
import org.dbunit.dataset.stream.IDataSetProducer;
import org.dbunit.dataset.xml.XmlDataSetWriter;
import org.dbunit.dataset.xml.XmlProducer;
import org.dbunit.operation.DatabaseOperation;
import org.dbunit.util.FileHelper;

public class DBExportImport {
	private static String TEST_DIR = DBExportImport.class.getResource("/").getPath();

	public static void main(String[] args) throws Exception {
		File file = new File(TEST_DIR + "backup.xml");

		Connection connection = DBUtil.getConnection();
		String[] tableNames = new String[] { "student" };
		// 导出指定的表的数据到xml文件
		exportTables(connection, tableNames, file);
		// 导出所有表的数据到xml文件
		// exportAllTables(file, connection);
		// 将xml数据文件中的数据导入到数据库中
		importData(file, connection);
	}

	/**
	 * <pre>
	 * 导出数据到指定文件
	 * 
	 * 在这个方法中指定了一个表名"room",如果有多个表可以通过参数或其他的方式按照这种方式继续增加。
	 * 这个文件是XML格式的。
	 * 具体格式说明或其他格式参见http://www.dbunit.org/components.html
	 * 
	 * 
	 * </pre>
	 * 
	 * @param connection
	 *            一个标准的java.sql.Connection
	 * @param tableNames
	 *            需要导出数据的表名数组
	 * @param file
	 *            一个标准的java.io.File
	 * @throws Exception
	 */
	public static void exportTables(Connection connection, String[] tableNames, File file) throws Exception {
		IDatabaseConnection databaseConnection = new DatabaseConnection(connection);
		QueryDataSet dataSet = new QueryDataSet(databaseConnection);
		if (null != tableNames && 0 < tableNames.length) {
			int tableNamesLength = tableNames.length;
			for (int i = 0; i < tableNamesLength; i++) {
				dataSet.addTable(tableNames[i]);
			}
		}
		Writer writer = new FileWriter(file);
		XmlDataSetWriter w = new XmlDataSetWriter(writer);
		w.write(dataSet);
		writer.flush();
		writer.close();
	}

	/**
	 * <pre>
	 * 导出数据库中的所有数据到指定文件
	 * 这个文件是XML格式的。
	 * 具体格式说明或其他格式参见http://www.dbunit.org/components.html
	 * 
	 * 这个方法可以把上面生成的XML文件导入到数据库中,
	 * 如果是其他格式的文件只需要更换IDataSetProducer的实现类就可以了。
	 * 具体格式请参见APIDOC在这个方法里使用了事务控制,保证数据的一致性。
	 * 
	 * </pre>
	 * 
	 * @param file
	 *            一个标准的java.io.File
	 * @param connection
	 *            一个标准的java.sql.Connection
	 * @throws Exception
	 */
	public static void exportAllTables(File file, Connection connection) throws Exception {
		IDatabaseConnection databaseConnection = new DatabaseConnection(connection);
		IDataSet dataSet = databaseConnection.createDataSet();
		Writer writer = new FileWriter(file);
		XmlDataSetWriter w = new XmlDataSetWriter(writer);
		w.write(dataSet);
		writer.flush();
		writer.close();
	}

	/**
	 * CsvDataSetWriter
	 * 
	 * <pre>
	 * 导出数据库中的所有数据到指定文件
	 * 这个文件是XML格式的。
	 * 具体格式说明或其他格式参见http://www.dbunit.org/components.html
	 * 
	 * 这个方法可以把上面生成的XML文件导入到数据库中,
	 * 如果是其他格式的文件只需要更换IDataSetProducer的实现类就可以了。
	 * 具体格式请参见APIDOC在这个方法里使用了事务控制,保证数据的一致性。
	 * 
	 * </pre>
	 * 
	 * @param file
	 *            一个标准的java.io.File
	 * @param connection
	 *            一个标准的java.sql.Connection
	 * @throws Exception
	 */
	public static void exportAllTablesToCsv(Connection connection, File file) throws Exception {
		IDatabaseConnection databaseConnection = new DatabaseConnection(connection);
		IDataSet dataSet = databaseConnection.createDataSet();
		CsvDataSetWriter w = new CsvDataSetWriter(file);
		w.write(dataSet);
	}

	/**
	 * 导入数据到数据库
	 * 
	 * @param file
	 *            一个标准的java.io.File
	 * @param connection
	 *            一个标准的java.sql.Connection
	 */
	public static void importData(File file, Connection connection) throws DatabaseUnitException, IOException, SQLException {
		IDataSetProducer dataSetProducer = new XmlProducer(FileHelper.createInputSource(file));
		IDataSet dataSet = new CachedDataSet(dataSetProducer);
		IDatabaseConnection databaseConnection = new DatabaseConnection(connection);
		DatabaseOperation operation = DatabaseOperation.CLEAN_INSERT;
		DatabaseOperation.TRANSACTION(operation);
		operation.execute(databaseConnection, dataSet);
		DatabaseOperation.CLOSE_CONNECTION(operation);
	}
	

}

Maven工程文件

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.coderdream</groupId>
	<artifactId>dbunit-export-import</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>DBUnitSample</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.24</version>
		</dependency>

		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.7.5</version>
		</dependency>

		<dependency>
			<groupId>org.dbunit</groupId>
			<artifactId>dbunit</artifactId>
			<version>2.4.8</version>
		</dependency>

	</dependencies>

</project>

数据库配置属性文件

dbutil.properties

db.classname=com.mysql.jdbc.Driver
db.url=jdbc:mysql://127.0.0.1:3306/dbup?characterEncoding=UTF-8
db.username=root
db.password=1234

数据库脚本

dbup.sql

/*
Navicat MySQL Data Transfer

Source Server         : localhost
Source Server Version : 50525
Source Host           : localhost:3306
Source Database       : dbup

Target Server Type    : MYSQL
Target Server Version : 50525
File Encoding         : 65001

Date: 2014-10-11 14:27:06
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `role`
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
  `id` varchar(20) NOT NULL DEFAULT '',
  `roleName` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES ('1', '管理员');
INSERT INTO `role` VALUES ('2', '普通用户');

-- ----------------------------
-- Table structure for `student`
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `id` varchar(20) NOT NULL DEFAULT '',
  `name` varchar(20) DEFAULT NULL,
  `sex` varchar(10) DEFAULT NULL,
  `birthday` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('1', '2', '3', '4');

-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` varchar(20) NOT NULL DEFAULT '',
  `name` varchar(20) DEFAULT NULL,
  `role_id` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `ref_id` (`role_id`),
  CONSTRAINT `ref_id` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', '张三', '1');
INSERT INTO `user` VALUES ('2', '李四', '2');

日志配置文件

log4j.properties

# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, A1

# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender

# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

运行结果

导出的xml文件backup.xml

<?xml version='1.0' encoding='UTF-8'?>
<dataset>
  <table name="student">
    <column>id</column>
    <column>name</column>
    <column>sex</column>
    <column>birthday</column>
    <row>
      <value>0001</value>
      <value>&#32705;&#20180;</value>
      <value>m</value>
      <value>1979-12-31</value>
    </row>
    <row>
      <value>0002</value>
      <value>&#29579;&#32736;&#33457;</value>
      <value>f</value>
      <value>1982-08-09</value>
    </row>
  </table>
</dataset>

参考文档

  1. 使用DBUnit进行数据库备份与恢复
  2. 用DBUnit做数据备份恢复工具

完整源代码