| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  | package com.yj.earth.common.util;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import cn.hutool.core.lang.UUID;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  | import java.sql.*;
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  | import java.time.LocalDateTime;
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | public class SQLiteConverter {
 | 
					
						
							|  |  |  |     private static final String JDBC_DRIVER = "org.sqlite.JDBC";
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  |     // 源数据库和目标数据库路径
 | 
					
						
							|  |  |  |     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;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  |     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) {
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  |             e.printStackTrace();
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  |             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();
 | 
					
						
							|  |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  |     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("目标表结构创建完成");
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  |      * 为 model 表的每个字段创建索引
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  |      */
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  |     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表索引创建完成");
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  |     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;
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  |     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 表");
 | 
					
						
							|  |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  |         System.out.println("\n成功转换 mode_types 表数据:" + count + "条记录");
 | 
					
						
							|  |  |  |         rs.close();
 | 
					
						
							|  |  |  |         sourceStmt.close();
 | 
					
						
							|  |  |  |         targetStmt.close();
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  |     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 表");
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         System.out.println("\n成功转换 models 表数据:" + count + "条记录");
 | 
					
						
							|  |  |  |         rs.close();
 | 
					
						
							|  |  |  |         sourceStmt.close();
 | 
					
						
							|  |  |  |         targetStmt.close();
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  |      * 显示进度信息
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  |      */
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  |     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);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-29 17:34:21 +08:00
										 |  |  |     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);
 | 
					
						
							| 
									
										
										
										
											2025-09-29 13:56:36 +08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | }
 |