Files
yjearth/src/main/java/com/yj/earth/common/convert/MilitaryConverter.java
2025-10-09 11:03:15 +08:00

294 lines
11 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.yj.earth.common.convert;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.Base64;
public class MilitaryConverter {
private static final String JDBC_DRIVER = "org.sqlite.JDBC";
// 源数据库和目标数据库路径
private String sourceDbPath;
private String targetDbPath;
// 批处理大小、可根据内存情况调整
private static final int BATCH_SIZE = 100;
public MilitaryConverter(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);
// 复制并转换数据
copyJunBiaoTypesData(sourceConn, targetConn);
copyJunBiaosData(sourceConn, targetConn);
// 为military表添加索引
createMilitaryTableIndexes(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();
// 创建military_type表
String sql = """
CREATE TABLE "military_type" (
"id" TEXT,
"name" TEXT,
"parent_id" TEXT,
"tree_index" INTEGER,
"created_at" TEXT,
"updated_at" TEXT,
PRIMARY KEY ("id")
);
""";
stmt.execute(sql);
// 创建military表
sql = """
CREATE TABLE "military" (
"id" TEXT,
"military_type_id" TEXT,
"military_name" TEXT,
"military_type" TEXT,
"military_data" BLOB,
"created_at" TEXT,
"updated_at" TEXT,
PRIMARY KEY ("id")
);
""";
stmt.execute(sql);
stmt.close();
System.out.println("目标表结构创建完成");
}
/**
* 为 military 表创建索引
*/
private void createMilitaryTableIndexes(Connection conn) throws SQLException {
System.out.println("开始创建索引...");
Statement stmt = conn.createStatement();
String sql = """
CREATE INDEX idx_military_covering ON military(
military_type_id,
id,
military_name,
military_type,
created_at,
updated_at
);
""";
stmt.execute(sql);
stmt.close();
System.out.println("military表索引创建完成");
}
private int getTotalRecords(Connection conn, String tableName) throws SQLException {
// 只统计未删除的数据
PreparedStatement stmt = conn.prepareStatement(
"SELECT COUNT(*) AS total FROM " + tableName + " WHERE deleted_at IS NULL"
);
ResultSet rs = stmt.executeQuery();
int total = rs.next() ? rs.getInt("total") : 0;
rs.close();
stmt.close();
return total;
}
/**
* 从jun_biao_types表复制数据到military_type表
*/
private void copyJunBiaoTypesData(Connection sourceConn, Connection targetConn) throws SQLException {
int totalRecords = getTotalRecords(sourceConn, "jun_biao_types");
System.out.println("开始转换 jun_biao_types 表数据、共" + totalRecords + "条记录");
// 查询未删除的类型数据
PreparedStatement sourceStmt = sourceConn.prepareStatement(
"SELECT * FROM jun_biao_types WHERE deleted_at IS NULL"
);
ResultSet rs = sourceStmt.executeQuery();
PreparedStatement targetStmt = targetConn.prepareStatement(
"INSERT INTO military_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"));
if ("-1".equals(rs.getString("p_id"))) {
targetStmt.setNull(3, Types.VARCHAR);
} else {
targetStmt.setString(3, rs.getString("p_id"));
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, "jun_biao_types 表");
}
}
System.out.println("\n成功转换 jun_biao_types 表数据:" + count + "条记录");
rs.close();
sourceStmt.close();
targetStmt.close();
}
/**
* 从jun_biaos表复制数据到military表
*/
private void copyJunBiaosData(Connection sourceConn, Connection targetConn) throws SQLException {
int totalRecords = getTotalRecords(sourceConn, "jun_biaos");
System.out.println("开始转换 jun_biaos 表数据、共" + totalRecords + "条记录");
// 对于大字段、使用向前滚动的结果集、避免缓存所有数据
PreparedStatement sourceStmt = sourceConn.prepareStatement(
"SELECT * FROM jun_biaos WHERE deleted_at IS NULL",
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY
);
sourceStmt.setFetchSize(100);
ResultSet rs = sourceStmt.executeQuery();
PreparedStatement targetStmt = targetConn.prepareStatement(
"INSERT INTO military (id, military_type_id, military_name, military_type, military_data, " +
"created_at, updated_at) " +
"VALUES (?, ?, ?, ?, ?, ?, ?)"
);
int count = 0;
while (rs.next()) {
targetStmt.setString(1, rs.getString("jun_biao_id")); // 关联ID对应
targetStmt.setString(2, rs.getString("p_id")); // 类型ID对应
targetStmt.setString(3, rs.getString("name")); // 名称对应
targetStmt.setString(4, "svg"); // 内容类型对应
byte[] dataBytes = rs.getBytes("data"); // 二进制数据对应
if (dataBytes != null) {
targetStmt.setBytes(5, convertBase64ToPlainSvg(dataBytes));
} else {
targetStmt.setNull(5, Types.BLOB);
}
targetStmt.setObject(6, LocalDateTime.now()); // 使用原始创建时间
targetStmt.setObject(7, LocalDateTime.now()); // 使用原始更新时间
// 添加到批处理
targetStmt.addBatch();
count++;
// 执行批处理
if (count % BATCH_SIZE == 0 || count == totalRecords) {
targetStmt.executeBatch();
displayProgress(count, totalRecords, "jun_biaos 表");
}
}
System.out.println("\n成功转换 jun_biaos 表数据:" + 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);
}
// Base64 SVG的前缀标识
private static final String SVG_BASE64_PREFIX = "data:image/svg+xml;base64,";
/**
* 将Base64格式的SVG字节数组转换为明文SVG字节数组
*
* @param base64SvgBytes 包含Base64编码的SVG字节数组可带前缀
* @return 解码后的明文SVG字节数组
* @throws IllegalArgumentException 如果输入不是有效的Base64格式或为空
*/
public static byte[] convertBase64ToPlainSvg(byte[] base64SvgBytes) {
// 验证输入参数
if (base64SvgBytes == null || base64SvgBytes.length == 0) {
throw new IllegalArgumentException("输入的Base64 SVG字节数组不能为空");
}
// 将字节数组转换为字符串、处理可能存在的前缀
String base64SvgStr = new String(base64SvgBytes, StandardCharsets.UTF_8);
String pureBase64Str = base64SvgStr;
// 移除前缀(如果存在)
if (base64SvgStr.startsWith(SVG_BASE64_PREFIX)) {
pureBase64Str = base64SvgStr.substring(SVG_BASE64_PREFIX.length());
}
try {
// 执行Base64解码并返回字节数组
return Base64.getDecoder().decode(pureBase64Str);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("无效的Base64格式: " + e.getMessage(), e);
}
}
public static void main(String[] args) {
// 源数据库路径
String sourcePath = "F:\\YJEarth新.junbiao";
// 目标数据库路径
String targetPath = "F:\\通用军标库.junbiao";
System.out.println("开始数据库转换...");
System.out.println("源数据库: " + sourcePath);
System.out.println("目标数据库: " + targetPath);
long startTime = System.currentTimeMillis();
// 创建转换器并执行转换
MilitaryConverter converter = new MilitaryConverter(sourcePath, targetPath);
converter.convert();
long endTime = System.currentTimeMillis();
double elapsedTime = (endTime - startTime) / 1000.0;
System.out.printf("转换完成、耗时: %.2f秒%n", elapsedTime);
}
}