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 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 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 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 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.李”、“李麒麟”和“一几许”的帮助!