JDBC複製資料庫(sqlite)
阿新 • • 發佈:2021-06-24
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.李”、“李麒麟”和“一幾許”的幫助!