zoukankan      html  css  js  c++  java
  • 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.李”、“李麒麟”和“一几许”的帮助!

  • 相关阅读:
    每天一个linux命令
    Python 面向对象-下篇
    Python 面向对象-上篇
    何时会发生隐式类型转换
    C++类型检查
    无符号保留原则
    bool类型为什么可以当做int
    在类的外部定义成员函数注意形式
    局部类
    命名规范
  • 原文地址:https://www.cnblogs.com/YuanShiRenY/p/JDBC_DBBackup.html
Copyright © 2011-2022 走看看