一個基於DBUnit的數據導出/導入工具類

轉載自 積木

http://jim19770812.blogspot.com/2009/12/dbunit.html

DBUnit是基於JUnit的擴展,提供了基於數據庫的測試數據的自動化測試,並且DBUnit提供了強大的導入導出數據功能,可以很容易的構造乾淨的數據測試環境。
除了使用DBUnit實現自動化的數據單元測試,還可以用來實現類似數據庫備份/恢復的功能,道理都是差不多的。

網上常見的幾個關於DBUnit的問題


1.因爲外鍵約束造成導入失敗
其實DBUnit是可以避免這個問題的,關鍵在於不要使用FlatXmlDataSet,改用CsvDataSetWriter就不會有外鍵問題了。
2.自己實現了基於SQL腳本的數據測試工具
我認爲這種做法不可取,首先是測試數據的準備時間太長,數據量較少的話還可以用用,如果數據量比較大,寫sql還不得累死?要是表結構再有了變化所有sql又得重新修改一遍。使用DBUnit就簡單多了,數據庫變了只要把新數據庫重新導出一遍就可以了,非常容易。


代碼如下:
package com.dbdata;

import java.io.File;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import javax.swing.JFileChooser;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.database.QueryDataSet;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.csv.CsvDataSet;
import org.dbunit.dataset.csv.CsvDataSetWriter;
import org.dbunit.operation.DatabaseOperation;

import com.gdw.common.util.FileUtil;

public class DBDataUtil {
    private IDatabaseConnection connection =null;

    /**
     * 打開連接,相當於JDBC的DriverManager.getConnection()
     * @param conn
     * @return
     */
    public boolean open(final Connection conn){
        try {
            this.connection = new DatabaseConnection(conn);
            return connection != null;
        } catch (DatabaseUnitException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 關閉連接,相當於JDBC的connection.close;
     * @return
     */
    public boolean close(){
        if (this.connection != null){
            try {
                this.connection.close();
                return true;
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return false;
        }
        return true;
    }

    /**
     * 導出數據到指定的目錄下
     * @param tableNames 表名列表,注意外鍵關係,要按照順序排列(先導出字典,再導出主表)
     * @param destFolder 導出目錄
     * @return
     */
    public boolean exp(final List tableNames, final File destFolder){
      QueryDataSet dataSet = new QueryDataSet(connection);
      try{
          for(String tableName : tableNames){
              dataSet.addTable(tableName);
          }
          CsvDataSetWriter.write(dataSet, destFolder);
          this.saveDefaultPath(destFolder.getParent());
          return true;
      }catch(Exception e){
          e.printStackTrace();
      }
      return false;
    }

    /**
     * 導入數據,會根據導出時的順序依次導入,如果出現了因外鍵約束而導入失敗的情況,請調整導出時的表順序
     * @param sourceFolder
     * @return
     */
    public boolean imp(final File sourceFolder){
      try{
          IDataSet dataSet = new CsvDataSet(sourceFolder);
          //準備讀入數據
          DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
          return true;
      }catch(Exception e){
          e.printStackTrace();
      }
      return false;
    }

    /**
     * 選擇打開目錄
     * @return
     */
    public static String showOpenFolder(){
        String defaultPath = loadDefaultPath();
        JFileChooser jf = new JFileChooser(defaultPath);
        jf.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        int ret = jf.showOpenDialog(null);
        if (ret != JFileChooser.APPROVE_OPTION){
            return null;
        }

        return jf.getSelectedFile().getAbsolutePath();
    }

    /**
     * 選擇保存目錄
     * @param defaultPath 默認目錄
     * @return
     */
    public static String showSaveFolder(){
        String defaultPath = loadDefaultPath();
        JFileChooser jf = new JFileChooser(defaultPath);
        jf.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        int ret = jf.showSaveDialog(null);
        if (ret != JFileChooser.APPROVE_OPTION){
            return null;
        }

        return jf.getSelectedFile().getAbsolutePath();
    }

    public static String loadDefaultPath(){
        File f = new File(".lastpath");
        System.out.println(f.getAbsolutePath());
        if (f.isFile() && f.exists()){
            return FileUtil.readAbsolutFile(f.getAbsolutePath());
        }
        return null;
    }

    public static void saveDefaultPath(final String defaultPath){
        File f = new File(".lastpath");
        FileUtil.writeFile(".lastpath", defaultPath);
        System.out.println(f.getAbsolutePath());
    }
}


導出代碼
package com.dbdata;

import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.ResourceBundle;

import com.gdw.common.util.StringUtil;

public class DataImporter {
    public boolean imp(final String jdbcClassName, final String url, final String userName, final String password, final String folder){
        try{
            Class.forName(jdbcClassName);
            Connection conn = DriverManager.getConnection(url, userName, password);
            DBDataUtil util = new DBDataUtil();
            util.open(conn);
            try{
                boolean ret = util.imp(new File(folder));
                return ret;
            }finally{
                util.close();
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return false;
    }

    public static void main(String[] args) {
        Connection conn = null;
        try{
            String folder = DBDataUtil.showOpenFolder();
            if (StringUtil.isNull(folder)){
                return;
            }
            ResourceBundle rs = ResourceBundle.getBundle("_dbutil");
            boolean ret = new DataImporter().imp(rs.getString("db.classname"), rs.getString("db.url"), rs.getString("db.username"), rs.getString("db.password"), folder);
            System.out.println(ret ? "導入成功!" : "導入失敗");
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}


導入代碼
package com.dbdata;

import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.LinkedList;
import java.util.List;
import java.util.ResourceBundle;

import com.gdw.common.util.StringUtil;

public class DataExporter {
    public boolean exp(final String jdbcClassName, final String url, final String userName, final String password, final List tableNames, final String folder){
        try{
            Class.forName(jdbcClassName);
            Connection conn = DriverManager.getConnection(url, userName, password);
            DBDataUtil util = new DBDataUtil();
            util.open(conn);
            try{
                boolean ret = util.exp(tableNames, new File(folder));
                return ret;
                //System.out.println(ret ? "導出成功!" : "導出失敗");
            }finally{
                util.close();
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return false;
    }

    public static void main(String[] args) {
        Connection conn = null;
        try{
            ResourceBundle rs = ResourceBundle.getBundle("_dbutil");
            List tableNames = new LinkedList();
            tableNames.add("muser");
            tableNames.add("mmenu");
            tableNames.add("mtable1");
            tableNames.add("mtable2");
            tableNames.add("mtable3");
            tableNames.add("mtable4");
            tableNames.add("mtable5");
            tableNames.add("mtable6");
            tableNames.add("mtable7");
            String folder = DBDataUtil.showSaveFolder();
            if (StringUtil.isNull(folder)){
                return;
            }
            boolean ret = new DataExporter().exp(rs.getString("db.classname"), rs.getString("db.url"), rs.getString("db.username"), rs.getString("db.password"), tableNames, folder);
            System.out.println(ret ? "導出成功!" : "導出失敗");
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}


_dbutil.properties 內容如下
db.classname=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8
db.username=root
db.password=jim


用DBUnit實現數據測試的用法

1.在數據庫中生成測試數據
2.用DataExporter導出測試數據
2.編寫單元測試
2.1.測試執行前使用DataExporter把業務表備份到臨時目錄
2.2.使用DataImporter導入測試數據
2.3.執行單元測試
2.4.使用DataImporter將先前做的備份數據恢復


經過本人測試,以上代碼可以在包含外鍵約束的mysql數據庫環境下運行正常。
如果你有興趣的話,還可以在此基礎上改成基於命令行或者圖形化界面的工具,這樣用起來更容易。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章