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(";
").append("CREATE TABLE ").append('"').append(tableName).append('"').append("(
");
            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(",
");
            }
            // PK & FK
            ResultSet foreignKeys = metaData.getImportedKeys(null, null, tableName);
            int FKNum = 0;
            while (foreignKeys.next()) FKNum++;
            createTableSQL.append(",
");
            /* add primary key */
            insertPrimaryKey(tableName);
            if (FKNum != 0)
                createTableSQL.append(",
");
            else
                createTableSQL.append('
');
            /* add foreign key */
            insertForeignKey(tableName, FKNum);
            createTableSQL.append(");
");
        } 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(",
");
                    else createTableSQL.append('
');
                }
            }
        } 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(");
");
                    }
                }
            }
        } 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(");
");
                }
            }
        } 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.李”、“李麒麟”和“一几许”的帮助!

原文地址:https://www.cnblogs.com/YuanShiRenY/p/JDBC_DBBackup.html