1. 程式人生 > 其它 >JDBC複製資料庫(sqlite)

JDBC複製資料庫(sqlite)

0. 要求

複製資料庫到相應資料夾下,要求利用(1)JDBC相關操作;(2)file檔案操作(建立並寫入資料庫、sql檔案)

生成:拷貝資料庫、sql檔案(含用於建立拷貝資料庫的所有命令)

1. 需要注意的幾點

(1)利用metaData查詢primary key, foreign key, index;

  參考連結:Extracting Database Metadata Using JDBC | Baeldung

  內含Metadata所有操作,本文不再贅述。

(2)根據外來鍵對資料庫中的表進行排序避免因外來鍵約束造成表建立失敗;

  參考連結:https://blog.csdn.net/m0_38014998/article/details/92393256

  實現根據外來鍵對錶進行排序。

(3)對其中特殊(不常見)欄位型別blob和clob的處理:轉二進位制/十六進位制。

2. 原始碼

程式入口:選擇資料庫、遞迴

// 啟動器:Launcher.java
public class Launcher {
    public static void main(String[] args) {
        System.out.println("【system】input the name of db you want to copy(e.g. Chinook)");
        new Main(new Scanner(System.in).nextLine());
        System.out.println("【system】any one else? y or n");
        if (new Scanner(System.in).nextLine().equals("y"))
            main(null);
        else
            System.out.println("bye.");
    }
}

功能實現

// 功能實現:Main.java
import java.io.FileWriter;
import java.io.IOException;
import java.sql.*;
import java.util.LinkedHashSet;
import java.util.Set;

public class Main {
    // connections
    private Connection con_sourceDB = null;
    private Connection con_backup = null;
    // metaData of db
    private DatabaseMetaData metaData = null;
    // num of column---end with "," or ")"
    private int columnNum = 0;
    // table in order
    private final LinkedHashSet<String> tableInOrder = new LinkedHashSet<>();
    // instructions
    private StringBuilder createTableSQL = new StringBuilder();
    private StringBuilder createIndexSQL = new StringBuilder();
    private StringBuilder insertValueSQL = new StringBuilder();

    // constructor-inlet
    public Main(String dbName) {
        connect(dbName);// connect to sqlite
        getTablesAndSort();// output: sorted_tables
        for (String tableName : tableInOrder) {
            System.out.println("【table name: " + tableName + "】");
            createTables(tableName);
            createIndex(tableName);
            insertValues(tableName);
            execute(dbName);
            createTableSQL = new StringBuilder();
            createIndexSQL = new StringBuilder();
            insertValueSQL = new StringBuilder();
        }
        System.out.println("【system】success");
    }

    // connect to db
    private void connect(String dbName) {
        try {
            Class.forName("org.sqlite.JDBC");
            con_sourceDB = DriverManager.getConnection("jdbc:sqlite:SourceDB/" + dbName + ".db"); // connect to the source database
            con_backup = DriverManager.getConnection("jdbc:sqlite:Backup/" + dbName + "_backup.db"); // generate the copied database
            metaData = con_sourceDB.getMetaData();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // sort according to foreign keys
    private void getTablesAndSort() {
        try {
            ResultSet tables = metaData.getTables(null, null, "%", new String[]{"TABLE"});
            while (tables.next()) {
                String tableName = tables.getString("TABLE_NAME");
                if (!tableInOrder.contains(tableName)) {
                    ResultSet tableForeignKey = metaData.getImportedKeys(null, null, tableName);
                    checkImportedKeys(tableForeignKey, tableInOrder, metaData, tableName);
                    tableInOrder.add(tableName);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // sort-single table
    private void checkImportedKeys(ResultSet tableForeignKey, Set<String> set, DatabaseMetaData metaData, String tableName) {
        try {
            while (tableForeignKey.next()) {
                String referenceTable = tableForeignKey.getString("PKTABLE_NAME");
                if (!set.contains(referenceTable)) {
                    if (referenceTable.equals(tableName)) set.add(tableName);
                    else addTable(set, metaData, referenceTable);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // add-recursive-checkImportedKeys
    private void addTable(Set<String> set, DatabaseMetaData metaData, String tableName) {
        try {
            ResultSet tableForeignKey = metaData.getImportedKeys(null, null, tableName);
            checkImportedKeys(tableForeignKey, set, metaData, tableName);
            set.add(tableName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // create table...
    private void createTables(String tableName) {
        try {
            //create table
            createTableSQL.append("DROP TABLE IF EXISTS " + '"').append(tableName).append('"').append(";\n").append("CREATE TABLE ").append('"').append(tableName).append('"').append("(\n");
            ResultSet rs = metaData.getColumns(null, null, tableName, null);
            columnNum = 0;
            int columnIndex = 0;
            while (rs.next()) columnNum++;
            rs = metaData.getColumns(null, null, tableName, null);
            while (rs.next()) {
                columnIndex++;
                String columnName = rs.getString("COLUMN_NAME");
                String columnType = rs.getString("TYPE_NAME");
                int nullable = rs.getInt("NULLABLE");
                createTableSQL.append(columnName).append(' ').append(columnType);
                if (nullable == 0)
                    createTableSQL.append(" NOT NULL");
                if (columnIndex < columnNum)
                    createTableSQL.append(",\n");
            }
            // PK & FK
            ResultSet foreignKeys = metaData.getImportedKeys(null, null, tableName);
            int FKNum = 0;
            while (foreignKeys.next()) FKNum++;
            createTableSQL.append(",\n");
            /* add primary key */
            insertPrimaryKey(tableName);
            if (FKNum != 0)
                createTableSQL.append(",\n");
            else
                createTableSQL.append('\n');
            /* add foreign key */
            insertForeignKey(tableName, FKNum);
            createTableSQL.append(");\n");
        } catch (Exception e) {
            System.out.println("fail to create table." + e.toString());
        }
    }

    // primary(key01, key02...)
    private void insertPrimaryKey(String tableName) {
        try {
            ResultSet primaryKeys = metaData.getPrimaryKeys(null, null, tableName);
            int PKNum = 0;
            while (primaryKeys.next()) PKNum++;
            if (PKNum != 0) {
                primaryKeys = metaData.getPrimaryKeys(null, null, tableName);
                createTableSQL.append("PRIMARY KEY(");
                int keyIndex = 0;
                while (primaryKeys.next()) {
                    keyIndex++;
                    if (keyIndex < PKNum) createTableSQL.append(primaryKeys.getString("COLUMN_NAME")).append(',');
                    else createTableSQL.append(primaryKeys.getString("COLUMN_NAME")).append(')');
                }
            }
        } catch (Exception e) {
            System.out.println("fail to insert primary key. " + e.toString());
        }
    }

    // foreign key(keyName) references tableName(keyName)
    private void insertForeignKey(String tableName, int numberOfFk) {
        try {
            if (numberOfFk != 0) {
                ResultSet foreignKeys = metaData.getImportedKeys(null, null, tableName);
                int keyIndex = 0;
                while (foreignKeys.next()) {
                    keyIndex++;
                    String fkColumnName = foreignKeys.getString("FKCOLUMN_NAME");
                    String pkTableName = foreignKeys.getString("PKTABLE_NAME");
                    String pkColumnName = foreignKeys.getString("PKCOLUMN_NAME");
                    createTableSQL.append("FOREIGN KEY(").append(fkColumnName).append(") REFERENCES ").append(pkTableName).append('(').append(pkColumnName).append(')');
                    if (keyIndex < numberOfFk) createTableSQL.append(",\n");
                    else createTableSQL.append('\n');
                }
            }
        } catch (Exception e) {
            System.out.println("fail to insert foreign key." + e.toString());
        }
    }

    // create index on...
    private void createIndex(String tableName) {
        try {
            ResultSet rsIndex = metaData.getIndexInfo(null, null, tableName, false, true);
            LinkedHashSet<String> indexset = new LinkedHashSet<>();
            while (rsIndex.next()) {
                String indexName = rsIndex.getString("INDEX_NAME");
                String autoIndexName = "sqlite_autoindex_" + tableName + "_1";
                if (!indexName.equals(autoIndexName))
                    indexset.add(rsIndex.getString("INDEX_NAME"));
            }

            for (String indexName : indexset) {
                rsIndex = metaData.getIndexInfo(null, null, tableName, false, true);
                int keyIndex = 0;
                int IndexColumnNum = 0;
                createIndexSQL.append("CREATE ");
                while (rsIndex.next()) {
                    String getindexName = rsIndex.getString("INDEX_NAME");
                    if (indexName.equals(getindexName)) {
                        IndexColumnNum++;
                        if (IndexColumnNum <= 1) {
                            boolean nonUnique = rsIndex.getBoolean("NON_UNIQUE");
                            if (!nonUnique)
                                createIndexSQL.append("UNIQUE INDEX ").append(indexName).append(" ON ").append(tableName).append('(');
                            else
                                createIndexSQL.append("INDEX ").append(indexName).append(" ON ").append(tableName).append('(');
                        }
                    }
                }
                rsIndex = metaData.getIndexInfo(null, null, tableName, false, true);
                while (rsIndex.next()) {
                    String getindexName = rsIndex.getString("INDEX_NAME");
                    String columnName = rsIndex.getString("COLUMN_NAME");
                    if (indexName.equals(getindexName)) {
                        keyIndex++;
                        if (keyIndex < IndexColumnNum) createIndexSQL.append(columnName).append(',');
                        else createIndexSQL.append(columnName).append(");\n");
                    }
                }
            }
        } catch (Exception e) {
            System.out.println("fail to create index." + e.toString());
        }
    }

    // insert into...
    private void insertValues(String tableName) {
        try {
            String query = "SELECT * FROM " + '"' + tableName + '"' + ';';
            Statement stmt = con_sourceDB.createStatement();
            ResultSet rs = stmt.executeQuery(query);
            ResultSetMetaData rsmeta = rs.getMetaData();
            while (rs.next()) {
                int rowIndex = 0;
                insertValueSQL.append("INSERT INTO " + '"').append(tableName).append('"').append(" VALUES").append('(');
                ResultSet rsColumns = metaData.getColumns(null, null, tableName, null);
                while (rsColumns.next()) {
                    rowIndex++;
                    String columnName = rsColumns.getString("COLUMN_NAME");
                    String typeName = rsmeta.getColumnTypeName(rowIndex);
                    Object object = rs.getObject(columnName);
                    String str = "";
                    if (object != null) str = object.toString();
                    if (typeName.equals("text") || typeName.equals("blob") || str.equals("\\N")) { //*
                        if (object != null) {
                            String s = rs.getString(columnName);
                            if (typeName.equals("blob")){
                                s = rs.getObject(columnName).toString();
                                // s = toBinary(s);
                                s = strToHexadecimal(s);
                            }
                            s = s.replace("'", "''");
                            insertValueSQL.append("'").append(s).append("'");
                        }
                    } else insertValueSQL.append(object);
                    if (rowIndex < columnNum) insertValueSQL.append(',');
                    else insertValueSQL.append(");\n");
                }
            }
        } catch (Exception e) {
            System.out.println("fail to insertValue." + e.toString());
        }
    }

    // blob to binary
    private String toBinary(String str) {
        char[] strChar = str.toCharArray();
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < strChar.length; i++) {
            result.append(Integer.toBinaryString(strChar[i])).append(" ");
        }
        return result.toString();
    }
    // blob to hex
    public static String strToHexadecimal(String str) {
        char[] chars = "0123456789ABCDEF".toCharArray();
        StringBuilder sb = new StringBuilder("");
        byte[] bs = str.getBytes();
        int bit;
        for (byte b : bs) {
            bit = (b & 0x0f0) >> 4;
            sb.append(chars[bit]);
            bit = b & 0x0f;
            sb.append(chars[bit]);
        }
        return sb.toString().trim();
    }

    // save & execute
    private void execute(String dbName) {
        // write to sql
        try {
            System.out.print("try to write in sql...");
            // file-writer
            FileWriter writer = new FileWriter("./Backup/" + dbName + "_backup.sql", true);
            writer.write(createTableSQL.toString());
            writer.write(createIndexSQL.toString());
            writer.write(insertValueSQL.toString());
            writer.close();
            System.out.println("[done]");
        } catch (IOException e) {
            System.out.println("fail to write SQL." + e.toString());
        }

        // generate db_backup
        try {
            System.out.print("try to generate table...");
            Statement backupStatement = con_backup.createStatement();
            backupStatement.executeUpdate(createTableSQL.toString());
            backupStatement.executeUpdate(createIndexSQL.toString());
            backupStatement.executeUpdate(insertValueSQL.toString());
            System.out.println("[done]");
        } catch (Exception e) {
            System.out.println("fail to generate table." + e.toString());
        }
    }
}

3. 放在最後

感謝“Dr.李”、“李麒麟”和“一幾許”的幫助!