diff --git a/pom.xml b/pom.xml index 9ae4217a..de470025 100644 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,12 @@ pdf-jar 1.0 - + + + org.xerial + sqlite-jdbc + 3.42.0.0 + org.apache.pdfbox diff --git a/src/main/java/Tools/DatabaseSynchronizer.java b/src/main/java/Tools/DatabaseSynchronizer.java new file mode 100644 index 00000000..959f5a19 --- /dev/null +++ b/src/main/java/Tools/DatabaseSynchronizer.java @@ -0,0 +1,271 @@ +package Tools; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +public class DatabaseSynchronizer { + // 数据库连接配置 + private static final String SQLITE_URL = "jdbc:sqlite:D:\\dsWork\\CcsEduData\\数据库与脚本\\edudb_gather_220100000000_full_fullreport.db"; + private static final String PG_URL = "jdbc:postgresql://10.10.14.71:5432/szjz_db"; + private static final String PG_USER = "postgres"; + private static final String PG_PASSWORD = "DsideaL147258369"; + + public void syncDatabase() { + // 要同步的表名列表 + List tables = List.of("教基1001", "教基4149", "教基3115", "教基2107"); + + try { + // 加载数据库驱动 + Class.forName("org.sqlite.JDBC"); + Class.forName("org.postgresql.Driver"); + + // 同步每个表 + for (String tableName : tables) { + syncTable(tableName); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void syncTable(String tableName) throws SQLException { + // 获取表结构和数据 + TableInfo tableInfo = getTableInfo(tableName); + List> data = getTableData(tableName); + + // 在PostgreSQL中创建表并插入数据 + createTableInPostgres(tableInfo); + insertDataToPostgres(tableInfo, data); + } + + private TableInfo getTableInfo(String tableName) throws SQLException { + TableInfo tableInfo = new TableInfo(tableName); + + try (Connection conn = DriverManager.getConnection(SQLITE_URL); + ResultSet rs = conn.getMetaData().getColumns(null, null, tableName, null)) { + + while (rs.next()) { + String columnName = rs.getString("COLUMN_NAME"); + String sqliteType = rs.getString("TYPE_NAME"); + // 转换SQLite类型到PostgreSQL类型 + String pgType = convertSqliteTypeToPg(sqliteType); + tableInfo.addColumn(columnName, pgType); + } + } + return tableInfo; + } + + + + private void createTableInPostgres(TableInfo tableInfo) throws SQLException { + StringBuilder createTableSQL = new StringBuilder(); + createTableSQL.append("CREATE TABLE IF NOT EXISTS ") + .append(tableInfo.tableName) + .append(" ("); + + for (int i = 0; i < tableInfo.columnNames.size(); i++) { + if (i > 0) createTableSQL.append(", "); + createTableSQL.append(tableInfo.columnNames.get(i)) + .append(" ") + .append(tableInfo.columnTypes.get(i)); + } + createTableSQL.append(")"); + + try (Connection conn = DriverManager.getConnection(PG_URL, PG_USER, PG_PASSWORD); + Statement stmt = conn.createStatement()) { + stmt.execute(createTableSQL.toString()); + } + } + private void insertDataToPostgres(TableInfo tableInfo, List> data) throws SQLException { + if (data.isEmpty()) { + System.out.println("没有数据需要插入"); + return; + } + + try (Connection conn = DriverManager.getConnection(PG_URL, PG_USER, PG_PASSWORD)) { + conn.setAutoCommit(false); + + StringBuilder insertSQL = new StringBuilder(); + insertSQL.append("INSERT INTO ") + .append(tableInfo.tableName) + .append(" ("); + + for (int i = 0; i < tableInfo.columnNames.size(); i++) { + if (i > 0) insertSQL.append(", "); + insertSQL.append(tableInfo.columnNames.get(i)); + } + + insertSQL.append(") VALUES ("); + + for (int i = 0; i < tableInfo.columnNames.size(); i++) { + if (i > 0) insertSQL.append(", "); + insertSQL.append("?"); + } + + insertSQL.append(")"); + + System.out.println("插入SQL: " + insertSQL); + + try (PreparedStatement pstmt = conn.prepareStatement(insertSQL.toString())) { + int batchSize = 1000; + int count = 0; + int totalInserted = 0; + + for (List row : data) { + if (row.size() != tableInfo.columnNames.size()) { + System.out.println("警告: 数据行列数不匹配"); + continue; + } + + for (int i = 0; i < row.size(); i++) { + Object value = row.get(i); + String columnType = tableInfo.columnTypes.get(i).toUpperCase(); + + try { + if (value == null) { + pstmt.setNull(i + 1, Types.NULL); + } + // 处理数值类型 + else if (columnType.contains("DOUBLE") || columnType.contains("NUMERIC") || + columnType.contains("DECIMAL") || columnType.contains("REAL")) { + if (value instanceof String) { + String strValue = (String) value; + if (strValue.isEmpty()) { + pstmt.setNull(i + 1, Types.DOUBLE); + } else { + try { + pstmt.setDouble(i + 1, Double.parseDouble(strValue)); + } catch (NumberFormatException e) { + pstmt.setNull(i + 1, Types.DOUBLE); + System.out.println("警告: 无法转换为数值类型: " + strValue); + } + } + } else if (value instanceof Number) { + pstmt.setDouble(i + 1, ((Number) value).doubleValue()); + } else { + pstmt.setNull(i + 1, Types.DOUBLE); + System.out.println("警告: 未知的数值类型: " + value.getClass()); + } + } + // 处理整数类型 + else if (columnType.contains("INTEGER") || columnType.contains("INT")) { + if (value instanceof String) { + String strValue = (String) value; + if (strValue.isEmpty()) { + pstmt.setNull(i + 1, Types.INTEGER); + } else { + try { + pstmt.setInt(i + 1, Integer.parseInt(strValue)); + } catch (NumberFormatException e) { + pstmt.setNull(i + 1, Types.INTEGER); + System.out.println("警告: 无法转换为整数类型: " + strValue); + } + } + } else if (value instanceof Number) { + pstmt.setInt(i + 1, ((Number) value).intValue()); + } else { + pstmt.setNull(i + 1, Types.INTEGER); + System.out.println("警告: 未知的整数类型: " + value.getClass()); + } + } + // 其他类型当作字符串处理 + else { + pstmt.setString(i + 1, value.toString()); + } + } catch (Exception e) { + System.out.println("警告: 设置值时出错: 列=" + tableInfo.columnNames.get(i) + + ", 值=" + value + ", 类型=" + columnType); + pstmt.setNull(i + 1, Types.NULL); + } + } + + pstmt.addBatch(); + + if (++count % batchSize == 0) { + pstmt.executeBatch(); + conn.commit(); + totalInserted += count; + count = 0; + System.out.println("已插入 " + totalInserted + " 行"); + } + } + + if (count > 0) { + pstmt.executeBatch(); + conn.commit(); + totalInserted += count; + } + + System.out.println("总共插入 " + totalInserted + " 行数据"); + } catch (SQLException e) { + conn.rollback(); + System.out.println("插入数据时出错: " + e.getMessage()); + throw e; + } + } + } + + // 修改 getTableData 方法,添加调试信息 + private List> getTableData(String tableName) throws SQLException { + List> data = new ArrayList<>(); + + try (Connection conn = DriverManager.getConnection(SQLITE_URL); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName)) { + + ResultSetMetaData metaData = rs.getMetaData(); + int columnCount = metaData.getColumnCount(); + + System.out.println("Table: " + tableName + ", Column count: " + columnCount); + for (int i = 1; i <= columnCount; i++) { + System.out.println("Column " + i + ": " + metaData.getColumnName(i) + + " (" + metaData.getColumnTypeName(i) + ")"); + } + + while (rs.next()) { + List row = new ArrayList<>(); + for (int i = 1; i <= columnCount; i++) { + row.add(rs.getObject(i)); + } + data.add(row); + } + + System.out.println("Read " + data.size() + " rows from SQLite"); + } + return data; + } + + private String convertSqliteTypeToPg(String sqliteType) { + // 类型转换映射 + return switch (sqliteType.toUpperCase()) { + case "INTEGER" -> "INTEGER"; + case "REAL" -> "DOUBLE PRECISION"; + case "TEXT" -> "TEXT"; + case "BLOB" -> "BYTEA"; + default -> "TEXT"; + }; + } + + // 表信息存储类 + private static class TableInfo { + String tableName; + List columnNames = new ArrayList<>(); + List columnTypes = new ArrayList<>(); + + TableInfo(String tableName) { + this.tableName = tableName; + } + + void addColumn(String name, String type) { + columnNames.add(name); + columnTypes.add(type); + } + } + + public static void main(String[] args) { + DatabaseSynchronizer synchronizer = new DatabaseSynchronizer(); + synchronizer.syncDatabase(); + } +} \ No newline at end of file