package com.yj.earth.common.util; import cn.hutool.core.lang.UUID; import java.sql.*; import java.time.LocalDateTime; public class SQLiteConverter { private static final String JDBC_DRIVER = "org.sqlite.JDBC"; // 源数据库和目标数据库路径 private String sourceDbPath; private String targetDbPath; // 批处理大小、可根据内存情况调整 private static final int BATCH_SIZE = 100; public SQLiteConverter(String sourceDbPath, String targetDbPath) { this.sourceDbPath = sourceDbPath; this.targetDbPath = targetDbPath; } public void convert() { Connection sourceConn = null; Connection targetConn = null; try { // 加载驱动 Class.forName(JDBC_DRIVER); // 连接源数据库和目标数据库 sourceConn = DriverManager.getConnection("jdbc:sqlite:" + sourceDbPath); targetConn = DriverManager.getConnection("jdbc:sqlite:" + targetDbPath); // 禁用自动提交、以便在出现错误时可以回滚 targetConn.setAutoCommit(false); // 创建目标表结构 createTargetTables(targetConn); // 复制并转换数据 copyModeTypesData(sourceConn, targetConn); copyModelsData(sourceConn, targetConn); // 为model表添加索引 createModelTableIndexes(targetConn); // 提交事务 targetConn.commit(); System.out.println("数据库转换成功!"); } catch (Exception e) { e.printStackTrace(); try { if (targetConn != null) { targetConn.rollback(); System.out.println("转换失败、已回滚操作!"); } } catch (SQLException ex) { ex.printStackTrace(); } } finally { // 关闭连接 try { if (sourceConn != null) sourceConn.close(); if (targetConn != null) targetConn.close(); } catch (SQLException e) { e.printStackTrace(); } } } private void createTargetTables(Connection conn) throws SQLException { System.out.println("开始创建目标表结构..."); Statement stmt = conn.createStatement(); String sql = """ CREATE TABLE "model_type" ( "id" TEXT, "name" TEXT, "parent_id" TEXT, "tree_index" INTEGER, "created_at" TEXT, "updated_at" TEXT, PRIMARY KEY ("id") ); """; stmt.execute(sql); sql = """ CREATE TABLE "model" ( "id" TEXT, "model_type_id" TEXT, "model_name" TEXT, "model_type" TEXT, "model_data" BLOB, "poster_type" TEXT, "poster_data" BLOB, "created_at" TEXT, "updated_at" TEXT, PRIMARY KEY ("id") ); """; stmt.execute(sql); stmt.close(); System.out.println("目标表结构创建完成"); } /** * 为 model 表的每个字段创建索引 */ private void createModelTableIndexes(Connection conn) throws SQLException { System.out.println("开始为创建索引..."); Statement stmt = conn.createStatement(); String sql = """ CREATE INDEX idx_model_covering ON model( model_type_id, id, model_name, model_type, poster_type, created_at, updated_at ); """; stmt.execute(sql); stmt.close(); System.out.println("model表索引创建完成"); } private int getTotalRecords(Connection conn, String tableName) throws SQLException { PreparedStatement stmt = conn.prepareStatement("SELECT COUNT(*) AS total FROM " + tableName); ResultSet rs = stmt.executeQuery(); int total = rs.next() ? rs.getInt("total") : 0; rs.close(); stmt.close(); return total; } private void copyModeTypesData(Connection sourceConn, Connection targetConn) throws SQLException { int totalRecords = getTotalRecords(sourceConn, "mode_types"); System.out.println("开始转换 mode_types 表数据、共" + totalRecords + "条记录"); PreparedStatement sourceStmt = sourceConn.prepareStatement("SELECT * FROM mode_types"); ResultSet rs = sourceStmt.executeQuery(); PreparedStatement targetStmt = targetConn.prepareStatement( "INSERT INTO model_type (id, name, parent_id, tree_index, created_at, updated_at) " + "VALUES (?, ?, ?, ?, ?, ?)" ); int count = 0; while (rs.next()) { targetStmt.setString(1, rs.getString("type_id")); targetStmt.setString(2, rs.getString("type_name")); targetStmt.setString(3, rs.getString("p_id")); targetStmt.setInt(4, 0); targetStmt.setObject(5, LocalDateTime.now()); targetStmt.setObject(6, LocalDateTime.now()); // 添加到批处理 targetStmt.addBatch(); count++; // 每达到批处理大小或最后一条记录时执行批处理 if (count % BATCH_SIZE == 0 || count == totalRecords) { targetStmt.executeBatch(); displayProgress(count, totalRecords, "mode_types 表"); } } System.out.println("\n成功转换 mode_types 表数据:" + count + "条记录"); rs.close(); sourceStmt.close(); targetStmt.close(); } private void copyModelsData(Connection sourceConn, Connection targetConn) throws SQLException { int totalRecords = getTotalRecords(sourceConn, "models"); System.out.println("开始转换 models 表数据、共" + totalRecords + "条记录"); // 对于大字段、使用向前滚动的结果集、避免缓存所有数据 PreparedStatement sourceStmt = sourceConn.prepareStatement( "SELECT * FROM models", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY ); sourceStmt.setFetchSize(100); ResultSet rs = sourceStmt.executeQuery(); PreparedStatement targetStmt = targetConn.prepareStatement( "INSERT INTO model (id, model_type_id, model_name, model_type, model_data, " + "poster_type, poster_data, created_at, updated_at) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)" ); int count = 0; while (rs.next()) { targetStmt.setString(1, rs.getString("id")); targetStmt.setString(2, rs.getString("p_id")); targetStmt.setString(3, rs.getString("model_name")); targetStmt.setString(4, rs.getString("model_type")); byte[] dataBytes = rs.getBytes("data"); if (dataBytes != null) { targetStmt.setBytes(5, dataBytes); } else { targetStmt.setNull(5, Types.BLOB); } targetStmt.setString(6, rs.getString("poster_type")); byte[] posterBytes = rs.getBytes("poster"); if (posterBytes != null) { targetStmt.setBytes(7, posterBytes); } targetStmt.setObject(8, LocalDateTime.now()); targetStmt.setObject(9, LocalDateTime.now()); // 添加到批处理 targetStmt.addBatch(); count++; // 执行批处理 if (count % BATCH_SIZE == 0 || count == totalRecords) { targetStmt.executeBatch(); displayProgress(count, totalRecords, "models 表"); } } System.out.println("\n成功转换 models 表数据:" + count + "条记录"); rs.close(); sourceStmt.close(); targetStmt.close(); } /** * 显示进度信息 */ private void displayProgress(int current, int total, String tableName) { double percentage = (double) current / total * 100; // 清除当前行并显示进度 System.out.printf("\r%s: 已完成 %.1f%% (%d/%d条)", tableName, percentage, current, total); } public static void main(String[] args) { // 源数据库路径 String sourcePath = "F:\\公司通用模型库.model"; // 目标数据库路径 String targetPath = "F:\\通用模型库.model"; System.out.println("开始数据库转换..."); System.out.println("源数据库: " + sourcePath); System.out.println("目标数据库: " + targetPath); long startTime = System.currentTimeMillis(); // 创建转换器并执行转换 SQLiteConverter converter = new SQLiteConverter(sourcePath, targetPath); converter.convert(); long endTime = System.currentTimeMillis(); double elapsedTime = (endTime - startTime) / 1000.0; System.out.printf("转换完成、耗时: %.2f秒%n", elapsedTime); } }