|
|
@@ -0,0 +1,885 @@
|
|
|
+package org.dromara.external.util;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.sql.*;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.*;
|
|
|
+
|
|
|
+public class DataMigration {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // SQL Server 连接信息
|
|
|
+ private static final String SQL_SERVER_URL = "jdbc:sqlserver://192.168.1.123:1433;databaseName=yoe_db";
|
|
|
+ private static final String SQL_SERVER_USER = "sa";
|
|
|
+ private static final String SQL_SERVER_PASS = "Sql123456";
|
|
|
+
|
|
|
+ // MySQL 连接信息
|
|
|
+ private static final String MYSQL_URL = "jdbc:mysql://127.0.0.1:3306/yoe_product_db?useSSL=false&serverTimezone=UTC";
|
|
|
+ private static final String MYSQL_USER = "root";
|
|
|
+ private static final String MYSQL_PASS = "root";
|
|
|
+
|
|
|
+ // 分页参数
|
|
|
+ private static final int BATCH_SIZE = 1000;
|
|
|
+
|
|
|
+
|
|
|
+ // === 全局 product_no -> product_id 映射(只读)===
|
|
|
+ private static volatile Map<String, Long> productNoToId;
|
|
|
+
|
|
|
+ // === 配置 ===
|
|
|
+ private static final int THREAD_COUNT = 8;
|
|
|
+ private static final int PAGE_SIZE = 10_000;
|
|
|
+
|
|
|
+ public static void main(String[] args) {
|
|
|
+// try (Connection sqlConn = DriverManager.getConnection(SQL_SERVER_URL, SQL_SERVER_USER, SQL_SERVER_PASS)) {
|
|
|
+// // 先迁移依赖表(品牌、分类、单位、售后)
|
|
|
+// try (Connection mysqlConn = DriverManager.getConnection(MYSQL_URL, MYSQL_USER, MYSQL_PASS)) {
|
|
|
+// loadMappings(mysqlConn);
|
|
|
+// }
|
|
|
+// // 再多线程迁移主表 product_info
|
|
|
+// migrateData(sqlConn); // 注意:现在只传 sqlConn(但内部线程会新建连接)
|
|
|
+// System.out.println("✅ 所有数据迁移完成!");
|
|
|
+//
|
|
|
+// } catch (Exception e) {
|
|
|
+// e.printStackTrace();
|
|
|
+// }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 1. 加载 product_no -> id 映射(从已迁移的 product_base 表)
|
|
|
+ loadProductNoMapping();
|
|
|
+ System.out.println("✅ 已加载 " + productNoToId.size() + " 个 product_no 映射");
|
|
|
+
|
|
|
+ // 2. 获取 ID 范围
|
|
|
+ RangeInfo range = getMssqlIdRange();
|
|
|
+ System.out.println("📊 总记录数: " + range.totalCount + ", ID 范围: [" + range.minId + ", " + range.maxId + "]");
|
|
|
+
|
|
|
+ // 3. 划分任务
|
|
|
+ List<TaskRange> tasks = splitTasks(range.minId, range.maxId, PAGE_SIZE);
|
|
|
+ System.out.println("🧩 共划分 " + tasks.size() + " 个任务");
|
|
|
+
|
|
|
+ // 4. 并行执行
|
|
|
+ ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
|
|
|
+ List<Future<Long>> futures = new ArrayList<>();
|
|
|
+
|
|
|
+ for (TaskRange task : tasks) {
|
|
|
+ futures.add(executor.submit(new PhotoMigrationTask(task)));
|
|
|
+ }
|
|
|
+
|
|
|
+ long total = 0;
|
|
|
+ for (Future<Long> f : futures) total += f.get();
|
|
|
+ executor.shutdown();
|
|
|
+
|
|
|
+ System.out.println("🎉 图片表迁移完成!共 " + total + " 条记录。");
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 售后服务迁移
|
|
|
+ * */
|
|
|
+ private static void migrateProductAfterSales(Connection source, Connection target) throws SQLException {
|
|
|
+
|
|
|
+ try (Connection sqlServerConn = source;
|
|
|
+ Connection mysqlConn = target) {
|
|
|
+
|
|
|
+ // Fetch data from SQL Server
|
|
|
+ String fetchSql = "SELECT id, after_sales_items, data_source, created, modify FROM product_after_sales";
|
|
|
+ try (Statement stmt = sqlServerConn.createStatement(); ResultSet rs = stmt.executeQuery(fetchSql)) {
|
|
|
+
|
|
|
+ // Insert data into MySQL
|
|
|
+ String insertSql = "INSERT INTO product_after_sales (id, after_sales_items, data_source, tenant_id, del_flag, create_time, update_time) VALUES (?, ?, ?, '000000', '0', ?, ?)";
|
|
|
+ try (PreparedStatement pstmt = mysqlConn.prepareStatement(insertSql)) {
|
|
|
+ while (rs.next()) {
|
|
|
+ int id = rs.getInt("id");
|
|
|
+ String afterSalesItems = rs.getString("after_sales_items");
|
|
|
+ String dataSource = rs.getString("data_source");
|
|
|
+ Timestamp createTime = rs.getTimestamp("created");
|
|
|
+ Timestamp updateTime = rs.getTimestamp("modify");
|
|
|
+
|
|
|
+ pstmt.setInt(1, id);
|
|
|
+ pstmt.setString(2, afterSalesItems);
|
|
|
+ pstmt.setString(3, dataSource);
|
|
|
+ pstmt.setTimestamp(4, createTime);
|
|
|
+ pstmt.setTimestamp(5, updateTime);
|
|
|
+
|
|
|
+ pstmt.addBatch();
|
|
|
+ }
|
|
|
+ pstmt.executeBatch();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (SQLException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分类迁移
|
|
|
+ * */
|
|
|
+ private static void migrateProductCategory(Connection source, Connection target) throws SQLException {
|
|
|
+ String selectSql = """
|
|
|
+ SELECT
|
|
|
+ id, category_no, category_name, parent_id, class_level,
|
|
|
+ is_show, is_show_gps, discount_rate, py_code, class_description,
|
|
|
+ data_source, created, modify,
|
|
|
+ one_lable1, one_lable2, one_link1, one_link2,
|
|
|
+ sort, color, purchase_no, purchase_name,
|
|
|
+ purchase_manager_no, purchase_manager_name, platform
|
|
|
+ FROM product_category
|
|
|
+ where data_source = 'youyi'
|
|
|
+ ORDER BY id
|
|
|
+ """;
|
|
|
+ String selectSql1 = "SELECT id,parent_id FROM product_category where data_source = 'youyi'and category_no =";
|
|
|
+
|
|
|
+ String insertSql = """
|
|
|
+ INSERT INTO product_category (
|
|
|
+ id, category_no, category_name, parent_id, ancestors,
|
|
|
+ class_level, is_show, is_show_gps, discount_rate, py_code,
|
|
|
+ class_description, data_source,
|
|
|
+ one_lable1, one_lable2, one_link1, one_link2,
|
|
|
+ sort, color, purchase_no, purchase_name,
|
|
|
+ purchase_manager_no, purchase_manager_name, platform,
|
|
|
+ tenant_id, del_flag, create_time, update_time
|
|
|
+ ) VALUES (
|
|
|
+ ?, ?, ?, ?, NULL,
|
|
|
+ ?, ?, ?, ?, ?,
|
|
|
+ ?, ?,
|
|
|
+ ?, ?, ?, ?,
|
|
|
+ ?, ?, ?, ?,
|
|
|
+ ?, ?, ?,
|
|
|
+ '000000', '0', ?, ?
|
|
|
+ )
|
|
|
+ """;
|
|
|
+ String updateSql1 =
|
|
|
+ "UPDATE product_category SET ancestors = 0 WHERE parent_id = 0;";
|
|
|
+ String updateSql2 = "UPDATE product_category AS child\n" +
|
|
|
+ "JOIN product_category AS parent \n" +
|
|
|
+ " ON child.parent_id = parent.id\n" +
|
|
|
+ "SET child.ancestors = CONCAT(parent.ancestors, ',', parent.id)\n" +
|
|
|
+ "WHERE child.parent_id != 0;";
|
|
|
+
|
|
|
+ try (PreparedStatement selectStmt = source.prepareStatement(selectSql);
|
|
|
+ ResultSet rs = selectStmt.executeQuery();
|
|
|
+ PreparedStatement insertStmt = target.prepareStatement(insertSql)) {
|
|
|
+
|
|
|
+ int batchCount = 0;
|
|
|
+ while (rs.next()) {
|
|
|
+ // id
|
|
|
+ insertStmt.setLong(1, rs.getInt("id"));
|
|
|
+
|
|
|
+ // strings
|
|
|
+ insertStmt.setString(2, rs.getString("category_no"));
|
|
|
+ insertStmt.setString(3, rs.getString("category_name"));
|
|
|
+
|
|
|
+
|
|
|
+ PreparedStatement selectStmt1 = source.prepareStatement(selectSql1 +"'" +rs.getString("parent_id") +"'");
|
|
|
+ ResultSet rs1 = selectStmt1.executeQuery();
|
|
|
+ Long parentId = 0L;
|
|
|
+ // 检查是否有结果行
|
|
|
+ if (rs1.next()) {
|
|
|
+ // parent_id: 尝试转为 Long
|
|
|
+ String parentIdS = rs.getString("parent_id");
|
|
|
+ String parentIdStr = rs1.getString("id");
|
|
|
+ System.out.println("parentId="+parentIdS);
|
|
|
+ System.out.println("parentIdStr="+parentIdStr);
|
|
|
+ if (parentIdStr != null && !parentIdStr.trim().isEmpty()) {
|
|
|
+ try {
|
|
|
+ parentId = Long.parseLong(parentIdStr.trim());
|
|
|
+ } catch (NumberFormatException ignored) {
|
|
|
+ System.err.println("⚠️ 无法转换 parent_id: " + parentIdStr + ",设为 NULL");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ insertStmt.setObject(4, parentId, Types.BIGINT);
|
|
|
+
|
|
|
+ // class_level
|
|
|
+ insertStmt.setInt(5, rs.getInt("class_level"));
|
|
|
+
|
|
|
+ // is_show (nullable)
|
|
|
+ Integer isShow = rs.getObject("is_show", Integer.class);
|
|
|
+ insertStmt.setObject(6, isShow, Types.INTEGER);
|
|
|
+
|
|
|
+ // is_show_gps (not null in source)
|
|
|
+ insertStmt.setInt(7, rs.getInt("is_show_gps"));
|
|
|
+
|
|
|
+ // discount_rate: 尝试转为 BigDecimal
|
|
|
+ String discStr = rs.getString("discount_rate");
|
|
|
+ BigDecimal discountRate = null;
|
|
|
+ if (discStr != null && !discStr.trim().isEmpty()) {
|
|
|
+ try {
|
|
|
+ // 支持 "0.85", "85%", "85" 等格式(按需调整)
|
|
|
+ String clean = discStr.trim().replace("%", "");
|
|
|
+ if (clean.contains(".")) {
|
|
|
+ discountRate = new BigDecimal(clean);
|
|
|
+ } else {
|
|
|
+ // 如果是整数,比如 "85",视为 85.00
|
|
|
+ discountRate = new BigDecimal(clean).setScale(2);
|
|
|
+ }
|
|
|
+ } catch (Exception ex) {
|
|
|
+ System.err.println("⚠️ 无法解析 discount_rate: " + discStr + ",设为 NULL");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ insertStmt.setObject(8, discountRate, Types.DECIMAL);
|
|
|
+
|
|
|
+ // 其他 varchar/text 字段
|
|
|
+ insertStmt.setString(9, rs.getString("py_code"));
|
|
|
+ insertStmt.setString(10, rs.getString("class_description"));
|
|
|
+ insertStmt.setString(11, rs.getString("data_source"));
|
|
|
+
|
|
|
+ insertStmt.setString(12, rs.getString("one_lable1"));
|
|
|
+ insertStmt.setString(13, rs.getString("one_lable2"));
|
|
|
+ insertStmt.setString(14, rs.getString("one_link1"));
|
|
|
+ insertStmt.setString(15, rs.getString("one_link2"));
|
|
|
+
|
|
|
+ insertStmt.setInt(16, rs.getInt("sort"));
|
|
|
+ insertStmt.setString(17, rs.getString("color"));
|
|
|
+ insertStmt.setString(18, rs.getString("purchase_no"));
|
|
|
+ insertStmt.setString(19, rs.getString("purchase_name"));
|
|
|
+ insertStmt.setString(20, rs.getString("purchase_manager_no"));
|
|
|
+ insertStmt.setString(21, rs.getString("purchase_manager_name"));
|
|
|
+
|
|
|
+ Integer platform = rs.getObject("platform", Integer.class);
|
|
|
+ insertStmt.setObject(22, platform, Types.INTEGER);
|
|
|
+
|
|
|
+ // 时间字段:datetime2(7) -> LocalDateTime -> Timestamp
|
|
|
+ Timestamp created = rs.getTimestamp("created");
|
|
|
+ Timestamp modified = rs.getTimestamp("modify");
|
|
|
+
|
|
|
+ insertStmt.setTimestamp(23, created);
|
|
|
+ insertStmt.setTimestamp(24, modified);
|
|
|
+
|
|
|
+ insertStmt.addBatch();
|
|
|
+
|
|
|
+ if (++batchCount % 1000 == 0) {
|
|
|
+ insertStmt.executeBatch();
|
|
|
+ System.out.println("已迁移 " + batchCount + " 条记录...");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 执行剩余批次
|
|
|
+ insertStmt.executeBatch();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 品牌迁移
|
|
|
+ * */
|
|
|
+ private static void migrateProductBrand(Connection source, Connection target) throws SQLException {
|
|
|
+ String selectSql = """
|
|
|
+ SELECT
|
|
|
+ id, brand_no, brand_name, brand_initials, brand_english_name,
|
|
|
+ recommend_value, brand_logo, brand_title, brand_big_image, brand_story,
|
|
|
+ is_show, brand_registrant, license, registration_certificate, expire_time,
|
|
|
+ created, modify, brand_describe, position, care, data_source
|
|
|
+ FROM product_brand
|
|
|
+ ORDER BY id
|
|
|
+ """;
|
|
|
+
|
|
|
+ String insertSql = """
|
|
|
+ INSERT INTO product_brand (
|
|
|
+ id, brand_no, brand_name, brand_initials, brand_english_name,
|
|
|
+ recommend_value, brand_logo, brand_title, brand_big_image, brand_story,
|
|
|
+ is_show, brand_registrant, license, registration_certificate, expire_time,
|
|
|
+ brand_describe, position, care, data_source,
|
|
|
+ tenant_id, del_flag, create_time, update_time
|
|
|
+ ) VALUES (
|
|
|
+ ?, ?, ?, ?, ?,
|
|
|
+ ?, ?, ?, ?, ?,
|
|
|
+ ?, ?, ?, ?, ?,
|
|
|
+ ?, ?, ?, ?,
|
|
|
+ '000000', '0', ?, ?
|
|
|
+ )
|
|
|
+ """;
|
|
|
+
|
|
|
+ try (PreparedStatement selectStmt = source.prepareStatement(selectSql);
|
|
|
+ ResultSet rs = selectStmt.executeQuery();
|
|
|
+ PreparedStatement insertStmt = target.prepareStatement(insertSql)) {
|
|
|
+
|
|
|
+ int count = 0;
|
|
|
+ while (rs.next()) {
|
|
|
+ insertStmt.setLong(1, rs.getInt("id"));
|
|
|
+ insertStmt.setString(2, rs.getString("brand_no"));
|
|
|
+ insertStmt.setString(3, rs.getString("brand_name"));
|
|
|
+ insertStmt.setString(4, rs.getString("brand_initials"));
|
|
|
+ insertStmt.setString(5, rs.getString("brand_english_name"));
|
|
|
+
|
|
|
+ insertStmt.setObject(6, rs.getObject("recommend_value"), Types.INTEGER);
|
|
|
+ insertStmt.setString(7, rs.getString("brand_logo"));
|
|
|
+ insertStmt.setString(8, rs.getString("brand_title"));
|
|
|
+ insertStmt.setString(9, rs.getString("brand_big_image"));
|
|
|
+ insertStmt.setString(10, rs.getString("brand_story"));
|
|
|
+
|
|
|
+ // is_show: 若为 NULL,则设为 0(符合 MySQL 默认逻辑)
|
|
|
+ Integer isShow = rs.getObject("is_show", Integer.class);
|
|
|
+ insertStmt.setInt(11, isShow != null ? isShow : 0);
|
|
|
+
|
|
|
+ insertStmt.setString(12, rs.getString("brand_registrant"));
|
|
|
+ insertStmt.setString(13, rs.getString("license"));
|
|
|
+ insertStmt.setString(14, rs.getString("registration_certificate"));
|
|
|
+
|
|
|
+ // 时间字段:datetime2(7) -> Timestamp
|
|
|
+ insertStmt.setTimestamp(15, rs.getTimestamp("expire_time"));
|
|
|
+ insertStmt.setString(16, rs.getString("brand_describe"));
|
|
|
+ insertStmt.setString(17, rs.getString("position"));
|
|
|
+
|
|
|
+ // care 是 NOT NULL,默认 0,但源表也有默认值,直接取
|
|
|
+ insertStmt.setInt(18, rs.getInt("care"));
|
|
|
+
|
|
|
+ insertStmt.setString(19, rs.getString("data_source"));
|
|
|
+
|
|
|
+ // create_time 和 update_time
|
|
|
+ insertStmt.setTimestamp(20, rs.getTimestamp("created"));
|
|
|
+ insertStmt.setTimestamp(21, rs.getTimestamp("modify"));
|
|
|
+
|
|
|
+ insertStmt.addBatch();
|
|
|
+
|
|
|
+ if (++count % 1000 == 0) {
|
|
|
+ insertStmt.executeBatch();
|
|
|
+ System.out.println("已迁移 " + count + " 条品牌记录...");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ insertStmt.executeBatch();
|
|
|
+ System.out.println("总计迁移 " + count + " 条记录。");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void migrateProductUnit(Connection source, Connection target) throws SQLException {
|
|
|
+ String selectSql = "SELECT id, unit_no, unit_name, data_source, is_thow, created, modify FROM product_unit ORDER BY id";
|
|
|
+ String insertSql = "INSERT INTO product_unit (id, unit_no, unit_name, data_source, is_show, tenant_id, del_flag, create_time, update_time) VALUES (?, ?, ?, ?, ?, '000000', '0', ?, ?)";
|
|
|
+
|
|
|
+ try (PreparedStatement selectStmt = source.prepareStatement(selectSql);
|
|
|
+ PreparedStatement insertStmt = target.prepareStatement(insertSql)) {
|
|
|
+
|
|
|
+ ResultSet rs = selectStmt.executeQuery();
|
|
|
+
|
|
|
+ while (rs.next()) {
|
|
|
+ insertStmt.setLong(1, rs.getInt("id"));
|
|
|
+ insertStmt.setString(2, rs.getString("unit_no"));
|
|
|
+ insertStmt.setString(3, rs.getString("unit_name"));
|
|
|
+ insertStmt.setString(4, rs.getString("data_source"));
|
|
|
+
|
|
|
+ // 假设 is_thow 为 1 表示显示,否则不显示
|
|
|
+ int isThow = rs.getInt("is_thow");
|
|
|
+ insertStmt.setString(5, isThow == 1 ? "1" : "0");
|
|
|
+
|
|
|
+ // 时间字段
|
|
|
+ insertStmt.setTimestamp(6, rs.getTimestamp("created"));
|
|
|
+ insertStmt.setTimestamp(7, rs.getTimestamp("modify") != null ? rs.getTimestamp("modify") : null);
|
|
|
+
|
|
|
+ insertStmt.addBatch();
|
|
|
+
|
|
|
+ if (rs.getRow() % 1000 == 0) { // 每1000条执行一次批量插入
|
|
|
+ insertStmt.executeBatch();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ insertStmt.executeBatch(); // 执行剩余记录
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 在类顶部添加线程池常量(可配置)
|
|
|
+ private static final ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
|
|
|
+
|
|
|
+ public static void migrateData(Connection mssqlConn) throws SQLException, InterruptedException {
|
|
|
+ // 先获取总记录数(用于计算分页)
|
|
|
+ long totalRecords = getTotalRecordCount(mssqlConn);
|
|
|
+ System.out.println("📊 总记录数: " + totalRecords);
|
|
|
+
|
|
|
+ long offset = 0;
|
|
|
+ List<Future<?>> futures = new ArrayList<>();
|
|
|
+
|
|
|
+ while (offset < totalRecords) {
|
|
|
+ long currentOffset = offset; // 必须是 final 或 effectively final
|
|
|
+ Future<?> future = executor.submit(() -> {
|
|
|
+ try {
|
|
|
+ processBatch(currentOffset, BATCH_SIZE);
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("❌ 批次 " + currentOffset + " 处理失败: " + e.getMessage());
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ futures.add(future);
|
|
|
+ offset += BATCH_SIZE;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 等待所有任务完成
|
|
|
+ for (Future<?> f : futures) {
|
|
|
+ try {
|
|
|
+ f.get(); // 抛出异常会中断
|
|
|
+ } catch (ExecutionException e) {
|
|
|
+ System.err.println("⚠️ 任务执行异常: " + e.getCause());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ executor.shutdown();
|
|
|
+ System.out.println("✅ 所有 product_info 数据迁移完成!");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取总记录数
|
|
|
+ private static long getTotalRecordCount(Connection conn) throws SQLException {
|
|
|
+ String countSql = "SELECT COUNT(*) FROM product_info";
|
|
|
+ try (Statement stmt = conn.createStatement();
|
|
|
+ ResultSet rs = stmt.executeQuery(countSql)) {
|
|
|
+ if (rs.next()) {
|
|
|
+ return rs.getLong(1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 单个批次处理逻辑(每个线程执行)
|
|
|
+ private static void processBatch(long offset, int batchSize) throws SQLException {
|
|
|
+ // 每个线程独立连接 MySQL
|
|
|
+ try (Connection mysqlConn = DriverManager.getConnection(MYSQL_URL, MYSQL_USER, MYSQL_PASS)) {
|
|
|
+ mysqlConn.setAutoCommit(false);
|
|
|
+
|
|
|
+ // 准备语句
|
|
|
+ PreparedStatement baseStmt = prepareBaseInsert(mysqlConn);
|
|
|
+ PreparedStatement priceStmt = preparePriceInsert(mysqlConn);
|
|
|
+ PreparedStatement extendStmt = prepareExtendInsert(mysqlConn);
|
|
|
+
|
|
|
+ // 从 SQL Server 读取当前批次(注意:这里需要重新建立连接 or 传入?)
|
|
|
+ // 由于原 mssqlConn 是主线程的,不能共享,所以每个线程也需独立连接 SQL Server
|
|
|
+ try (Connection sqlConn = DriverManager.getConnection(SQL_SERVER_URL, SQL_SERVER_USER, SQL_SERVER_PASS)) {
|
|
|
+ String sql = "SELECT * FROM product_info ORDER BY id OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
|
|
|
+ try (PreparedStatement selectStmt = sqlConn.prepareStatement(sql)) {
|
|
|
+ selectStmt.setLong(1, offset);
|
|
|
+ selectStmt.setInt(2, batchSize);
|
|
|
+
|
|
|
+ try (ResultSet rs = selectStmt.executeQuery()) {
|
|
|
+ boolean hasData = false;
|
|
|
+ while (rs.next()) {
|
|
|
+ hasData = true;
|
|
|
+ setBaseValues(baseStmt, rs);
|
|
|
+ baseStmt.addBatch();
|
|
|
+
|
|
|
+ setPriceValues(priceStmt, rs);
|
|
|
+ priceStmt.addBatch();
|
|
|
+
|
|
|
+ setExtendValues(extendStmt, rs);
|
|
|
+ extendStmt.addBatch();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hasData) {
|
|
|
+ baseStmt.executeBatch();
|
|
|
+ priceStmt.executeBatch();
|
|
|
+ extendStmt.executeBatch();
|
|
|
+ mysqlConn.commit();
|
|
|
+ System.out.println("✅ 线程 " + Thread.currentThread().getName() +
|
|
|
+ " 完成批次 offset=" + offset + ",迁移 " + batchSize + " 条");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ // 关闭所有 PreparedStatement
|
|
|
+ try { baseStmt.close(); } catch (Exception ignored) {}
|
|
|
+ try { priceStmt.close(); } catch (Exception ignored) {}
|
|
|
+ try { extendStmt.close(); } catch (Exception ignored) {}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // === product_base 插入准备 ===
|
|
|
+ private static PreparedStatement prepareBaseInsert(Connection conn) throws SQLException {
|
|
|
+ String sql = """
|
|
|
+ INSERT INTO product_base (
|
|
|
+ id, product_no, item_name,
|
|
|
+ brand_id, top_category_id, medium_category_id, bottom_category_id,
|
|
|
+ unit_id, product_image,
|
|
|
+ is_self, product_review_status,
|
|
|
+ home_recommended, category_recommendation, cart_recommendation,
|
|
|
+ recommended_product_order, is_popular, is_new, product_status,
|
|
|
+ data_source, tenant_id, del_flag,
|
|
|
+ create_time, update_time
|
|
|
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
|
+ """;
|
|
|
+ return conn.prepareStatement(sql);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void setBaseValues(PreparedStatement stmt, ResultSet rs) throws SQLException {
|
|
|
+ long newId = rs.getLong("id"); // 注意:MySQL 用 BIGINT,SQL Server 是 INT,但值兼容
|
|
|
+ stmt.setLong(1, newId);
|
|
|
+ stmt.setString(2, rs.getString("product_no"));
|
|
|
+ stmt.setString(3, rs.getString("item_name"));
|
|
|
+
|
|
|
+ // 注意:brand_no / cate_no 是字符串,但目标表是 bigint(ID)。这里假设你后续会通过字典映射。
|
|
|
+ // 如果没有映射关系,暂时设为 NULL 或 0。你可以根据实际业务替换为 lookupBrandId(rs.getString("brand_no")) 等。
|
|
|
+// 改为:
|
|
|
+ String brandNo = rs.getString("brand_no");
|
|
|
+ stmt.setObject(4, brandNoToId.get(brandNo), Types.BIGINT);
|
|
|
+
|
|
|
+ String topCateNo = rs.getString("top_cate_no");
|
|
|
+ stmt.setObject(5, categoryNoToId.get(topCateNo), Types.BIGINT);
|
|
|
+
|
|
|
+ String mediumCateNo = rs.getString("medium_cate_no");
|
|
|
+ stmt.setObject(6, categoryNoToId.get(mediumCateNo), Types.BIGINT);
|
|
|
+
|
|
|
+ String bottomCateNo = rs.getString("bottom_cate_no");
|
|
|
+ stmt.setObject(7, categoryNoToId.get(bottomCateNo), Types.BIGINT);
|
|
|
+
|
|
|
+ String unitNo = rs.getString("unit_no");
|
|
|
+ Long unitId = unitNoToId.get(unitNo);
|
|
|
+ stmt.setObject(8, unitId, Types.BIGINT);
|
|
|
+ stmt.setString(9, rs.getString("product_image"));
|
|
|
+
|
|
|
+ stmt.setString(10, intToFlag(rs.getInt("IsSelf")));
|
|
|
+ stmt.setString(11, String.valueOf(rs.getInt("product_review_status")));
|
|
|
+
|
|
|
+ stmt.setString(12, intToFlag(rs.getInt("home_recommended")));
|
|
|
+ stmt.setString(13, intToFlag(rs.getInt("category_recommendation")));
|
|
|
+ stmt.setString(14, intToFlag(rs.getInt("cart_recommendation")));
|
|
|
+
|
|
|
+ stmt.setInt(15, rs.getInt("recommended_product_order"));
|
|
|
+ stmt.setString(16, intToFlag(rs.getInt("is_popular")));
|
|
|
+ stmt.setString(17, intToFlag(rs.getObject("is_new") == null ? 0 : rs.getInt("is_new")));
|
|
|
+ stmt.setString(18, rs.getObject("product_status") == null ? "0" : String.valueOf(rs.getInt("product_status")));
|
|
|
+
|
|
|
+ stmt.setString(19, rs.getString("data_source") == null ? "youyi" : rs.getString("data_source"));
|
|
|
+ stmt.setString(20, "000000"); // tenant_id
|
|
|
+ stmt.setString(21, "0"); // del_flag
|
|
|
+
|
|
|
+ stmt.setTimestamp(22, rs.getTimestamp("created"));
|
|
|
+ stmt.setTimestamp(23, rs.getTimestamp("modify"));
|
|
|
+ }
|
|
|
+
|
|
|
+ // === product_price_inventory 插入准备 ===
|
|
|
+ private static PreparedStatement preparePriceInsert(Connection conn) throws SQLException {
|
|
|
+ String sql = """
|
|
|
+ INSERT INTO product_price_inventory (
|
|
|
+ product_id,
|
|
|
+ market_price, member_price, min_selling_price,
|
|
|
+ purchasing_price, max_purchase_price,
|
|
|
+ total_inventory, now_inventory, virtual_inventory,
|
|
|
+ min_order_quantity, tax_rate, currency,
|
|
|
+ tenant_id, del_flag, create_time, update_time
|
|
|
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
|
+ """;
|
|
|
+ return conn.prepareStatement(sql);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void setPriceValues(PreparedStatement stmt, ResultSet rs) throws SQLException {
|
|
|
+ long productId = rs.getLong("id");
|
|
|
+ stmt.setLong(1, productId);
|
|
|
+
|
|
|
+ stmt.setBigDecimal(2, toDecimal(rs.getString("market_price")));
|
|
|
+ stmt.setBigDecimal(3, toDecimal(rs.getString("member_price")));
|
|
|
+ stmt.setBigDecimal(4, toDecimal(rs.getString("min_selling_price")));
|
|
|
+ stmt.setBigDecimal(5, toDecimal(rs.getString("purchasing_price")));
|
|
|
+ stmt.setBigDecimal(6, toDecimal(rs.getString("max_purchase_price")));
|
|
|
+
|
|
|
+ stmt.setInt(7, rs.getInt("total_inventory"));
|
|
|
+ stmt.setInt(8, rs.getInt("now_inventory"));
|
|
|
+ stmt.setInt(9, rs.getInt("virtual_inventory"));
|
|
|
+
|
|
|
+ stmt.setInt(10, safeInt(rs.getString("min_order_quantity"), 1));
|
|
|
+ stmt.setBigDecimal(11, toDecimalPercent(rs.getString("tax_rate"))); // 如 "13" → 13.00%
|
|
|
+ stmt.setString(12, rs.getString("currency") == null ? "CNY" : rs.getString("currency"));
|
|
|
+
|
|
|
+ stmt.setString(13, "000000");
|
|
|
+ stmt.setString(14, "0");
|
|
|
+ stmt.setTimestamp(15, rs.getTimestamp("created"));
|
|
|
+ stmt.setTimestamp(16, rs.getTimestamp("modify"));
|
|
|
+ }
|
|
|
+
|
|
|
+ // === product_extend 插入准备 ===
|
|
|
+ private static PreparedStatement prepareExtendInsert(Connection conn) throws SQLException {
|
|
|
+ String sql = """
|
|
|
+ INSERT INTO product_extend (
|
|
|
+ product_id,
|
|
|
+ promotion_title, invoice_name, invoice_type, specifications_code,
|
|
|
+ bar_coding, product_description,
|
|
|
+ product_weight, weight_unit, product_volume, volume_unit,
|
|
|
+ after_sales_service, service_guarantee,
|
|
|
+ is_install_service, install_amount, distribution_price,
|
|
|
+ standard_sizes, gram_weight, opacity,
|
|
|
+ is_customize, custom_description,
|
|
|
+ product_profit, report_require, review_comments,
|
|
|
+ supplier_no, push_status, invoice_specs,
|
|
|
+ increment, purchase_no, purchase_name, supplier_name,
|
|
|
+ purchase_manager_no, purchase_manager_name,
|
|
|
+ reference_link, sales_volume, delivery_time, pit_time,
|
|
|
+ data_source, create_supplier, other_info,
|
|
|
+ tenant_id, del_flag, create_time, update_time
|
|
|
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
|
+ """;
|
|
|
+ return conn.prepareStatement(sql);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void setExtendValues(PreparedStatement stmt, ResultSet rs) throws SQLException {
|
|
|
+ long productId = rs.getLong("id");
|
|
|
+ stmt.setLong(1, productId);
|
|
|
+
|
|
|
+ stmt.setString(2, rs.getString("promotion_title"));
|
|
|
+ stmt.setString(3, rs.getString("invoice_name"));
|
|
|
+ stmt.setString(4, rs.getString("invoice_type"));
|
|
|
+ stmt.setString(5, rs.getString("specifications_code"));
|
|
|
+ stmt.setString(6, rs.getString("bar_coding"));
|
|
|
+ stmt.setString(7, rs.getString("product_description"));
|
|
|
+ stmt.setString(8, rs.getString("product_weight"));
|
|
|
+ stmt.setString(9, rs.getString("weight_unit"));
|
|
|
+ stmt.setString(10, rs.getString("product_volume"));
|
|
|
+ stmt.setString(11, rs.getString("volume_unit"));
|
|
|
+ stmt.setString(12, rs.getString("After_sales_service")); // 注意大小写
|
|
|
+ stmt.setString(13, rs.getString("service_guarantee"));
|
|
|
+
|
|
|
+ stmt.setString(14, intToFlag(rs.getInt("is_install_service")));
|
|
|
+ stmt.setString(15, rs.getString("install_amount"));
|
|
|
+ stmt.setString(16, rs.getString("distribution_price"));
|
|
|
+
|
|
|
+ stmt.setString(17, rs.getString("standard_sizes"));
|
|
|
+ stmt.setString(18, rs.getString("gram_weight"));
|
|
|
+ stmt.setString(19, rs.getString("opacity"));
|
|
|
+
|
|
|
+ stmt.setString(20, intToFlag(rs.getInt("is_customize")));
|
|
|
+ stmt.setString(21, rs.getString("custom_description"));
|
|
|
+
|
|
|
+ stmt.setString(22, rs.getString("product_profit"));
|
|
|
+ stmt.setString(23, rs.getString("report_require"));
|
|
|
+ stmt.setString(24, rs.getString("review_comments"));
|
|
|
+
|
|
|
+ stmt.setString(25, rs.getString("supplier_no"));
|
|
|
+ stmt.setString(26, rs.getObject("push_status") == null ? null : String.valueOf(rs.getInt("push_status")));
|
|
|
+ stmt.setString(27, rs.getString("invoice_specs"));
|
|
|
+
|
|
|
+ stmt.setObject(28, rs.getObject("increment"));
|
|
|
+ stmt.setString(29, rs.getString("purchase_no"));
|
|
|
+ stmt.setString(30, rs.getString("purchase_name"));
|
|
|
+ stmt.setString(31, rs.getString("supplier_name"));
|
|
|
+ stmt.setString(32, rs.getString("purchase_manager_no"));
|
|
|
+ stmt.setString(33, rs.getString("purchase_manager_name"));
|
|
|
+ stmt.setString(34, rs.getString("ReferenceLink")); // 注意大小写
|
|
|
+ stmt.setObject(35, rs.getObject("SalesVolume")); // 可能为 null
|
|
|
+ stmt.setString(36, rs.getString("DeliveryTime"));
|
|
|
+ stmt.setTimestamp(37, rs.getTimestamp("PitTime"));
|
|
|
+
|
|
|
+ stmt.setString(38, rs.getString("data_source"));
|
|
|
+ stmt.setString(39, rs.getString("CreateSupplier"));
|
|
|
+ stmt.setString(40, rs.getString("Other"));
|
|
|
+
|
|
|
+ stmt.setString(41, "000000");
|
|
|
+ stmt.setString(42, "0");
|
|
|
+ stmt.setTimestamp(43, rs.getTimestamp("created"));
|
|
|
+ stmt.setTimestamp(44, rs.getTimestamp("modify"));
|
|
|
+ }
|
|
|
+
|
|
|
+ // === 工具方法 ===
|
|
|
+
|
|
|
+ private static String intToFlag(int value) {
|
|
|
+ return value == 1 ? "1" : "0";
|
|
|
+ }
|
|
|
+
|
|
|
+ private static BigDecimal toDecimal(String str) {
|
|
|
+ if (str == null || str.trim().isEmpty()) return null;
|
|
|
+ try {
|
|
|
+ return new BigDecimal(str.trim());
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static BigDecimal toDecimalPercent(String str) {
|
|
|
+ // 假设 tax_rate 是 "13" 表示 13%,存为 13.00
|
|
|
+ BigDecimal bd = toDecimal(str);
|
|
|
+ return bd; // 如果需要百分比小数(如 0.13),则除以 100
|
|
|
+ }
|
|
|
+
|
|
|
+ private static int safeInt(String str, int defaultValue) {
|
|
|
+ if (str == null || str.trim().isEmpty()) return defaultValue;
|
|
|
+ try {
|
|
|
+ return Integer.parseInt(str.trim());
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ return defaultValue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 在 ProductMigration 类中添加以下字段
|
|
|
+ private static Map<String, Long> brandNoToId = new HashMap<>();
|
|
|
+ private static Map<String, Long> categoryNoToId = new HashMap<>();
|
|
|
+ private static Map<String, Long> unitNoToId = new HashMap<>();
|
|
|
+
|
|
|
+ private static void loadMappings(Connection mysqlConn) throws SQLException {
|
|
|
+ System.out.println("🔄 正在加载品牌、分类、单位映射...");
|
|
|
+
|
|
|
+ // 加载品牌
|
|
|
+ try (PreparedStatement stmt = mysqlConn.prepareStatement("SELECT brand_no, id FROM product_brand WHERE del_flag = '0'")) {
|
|
|
+ ResultSet rs = stmt.executeQuery();
|
|
|
+ while (rs.next()) {
|
|
|
+ brandNoToId.put(rs.getString("brand_no"), rs.getLong("id"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载分类(所有层级)
|
|
|
+ try (PreparedStatement stmt = mysqlConn.prepareStatement("SELECT category_no, id FROM product_category WHERE del_flag = '0'")) {
|
|
|
+ ResultSet rs = stmt.executeQuery();
|
|
|
+ while (rs.next()) {
|
|
|
+ categoryNoToId.put(rs.getString("category_no"), rs.getLong("id"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载单位
|
|
|
+ try (PreparedStatement stmt = mysqlConn.prepareStatement("SELECT unit_no, id FROM product_unit WHERE del_flag = '0'")) {
|
|
|
+ ResultSet rs = stmt.executeQuery();
|
|
|
+ while (rs.next()) {
|
|
|
+ unitNoToId.put(rs.getString("unit_no"), rs.getLong("id"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ System.out.println("✅ 品牌映射数量: " + brandNoToId.size());
|
|
|
+ System.out.println("✅ 分类映射数量: " + categoryNoToId.size());
|
|
|
+ System.out.println("✅ 单位映射数量: " + unitNoToId.size());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 加载 product_no -> product_base.id 映射
|
|
|
+ private static void loadProductNoMapping() throws SQLException {
|
|
|
+ try (Connection mysqlConn = DriverManager.getConnection(MYSQL_URL, MYSQL_USER, MYSQL_PASS)) {
|
|
|
+ productNoToId = new ConcurrentHashMap<>();
|
|
|
+ String sql = "SELECT product_no, id FROM product_base WHERE del_flag = '0'";
|
|
|
+ try (PreparedStatement stmt = mysqlConn.prepareStatement(sql);
|
|
|
+ ResultSet rs = stmt.executeQuery()) {
|
|
|
+ while (rs.next()) {
|
|
|
+ productNoToId.put(rs.getString("product_no"), rs.getLong("id"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static RangeInfo getMssqlIdRange() throws SQLException {
|
|
|
+ try (Connection conn = DriverManager.getConnection(SQL_SERVER_URL, SQL_SERVER_USER, SQL_SERVER_PASS);
|
|
|
+ Statement stmt = conn.createStatement();
|
|
|
+ ResultSet rs = stmt.executeQuery("SELECT MIN(id) min_id, MAX(id) max_id, COUNT(*) total FROM product_photos")) {
|
|
|
+ if (rs.next()) {
|
|
|
+ return new RangeInfo(rs.getLong("min_id"), rs.getLong("max_id"), rs.getLong("total"));
|
|
|
+ }
|
|
|
+ throw new RuntimeException("无法获取 ID 范围");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static List<TaskRange> splitTasks(long minId, long maxId, int pageSize) {
|
|
|
+ List<TaskRange> tasks = new ArrayList<>();
|
|
|
+ for (long start = minId; start <= maxId; start += pageSize) {
|
|
|
+ long end = Math.min(start + pageSize - 1, maxId);
|
|
|
+ tasks.add(new TaskRange(start, end));
|
|
|
+ }
|
|
|
+ return tasks;
|
|
|
+ }
|
|
|
+
|
|
|
+ // --- 内部类 ---
|
|
|
+ static class RangeInfo {
|
|
|
+ final long minId, maxId, totalCount;
|
|
|
+ RangeInfo(long minId, long maxId, long totalCount) {
|
|
|
+ this.minId = minId;
|
|
|
+ this.maxId = maxId;
|
|
|
+ this.totalCount = totalCount;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static class TaskRange {
|
|
|
+ final long startId, endId;
|
|
|
+ TaskRange(long startId, long endId) {
|
|
|
+ this.startId = startId;
|
|
|
+ this.endId = endId;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // --- 迁移任务 ---
|
|
|
+ static class PhotoMigrationTask implements Callable<Long> {
|
|
|
+ private final TaskRange range;
|
|
|
+
|
|
|
+ PhotoMigrationTask(TaskRange range) {
|
|
|
+ this.range = range;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Long call() throws Exception {
|
|
|
+ Thread.currentThread().setName("PhotoThread-" + range.startId);
|
|
|
+ long count = 0;
|
|
|
+
|
|
|
+ try (
|
|
|
+ Connection mssql = DriverManager.getConnection(SQL_SERVER_URL, SQL_SERVER_USER, SQL_SERVER_PASS);
|
|
|
+ Connection mysql = DriverManager.getConnection(MYSQL_URL, MYSQL_USER, MYSQL_PASS)
|
|
|
+ ) {
|
|
|
+ mysql.setAutoCommit(false);
|
|
|
+
|
|
|
+ String selectSql = """
|
|
|
+ SELECT id, image_no, product_no, image_url,
|
|
|
+ product_details_pc, product_details_app, created, modify, spec
|
|
|
+ FROM product_photos
|
|
|
+ WHERE id BETWEEN ? AND ?
|
|
|
+ ORDER BY id
|
|
|
+ """;
|
|
|
+
|
|
|
+ try (PreparedStatement sel = mssql.prepareStatement(selectSql)) {
|
|
|
+ sel.setLong(1, range.startId);
|
|
|
+ sel.setLong(2, range.endId);
|
|
|
+ ResultSet rs = sel.executeQuery();
|
|
|
+
|
|
|
+ String insertSql = """
|
|
|
+ INSERT INTO product_photos (
|
|
|
+ product_id,image_no , product_no, image_url,
|
|
|
+ product_details_pc, product_details_app, spec,
|
|
|
+ tenant_id, status, del_flag,
|
|
|
+ create_time, update_time, platform_code
|
|
|
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
|
+ """;
|
|
|
+
|
|
|
+ PreparedStatement ins = mysql.prepareStatement(insertSql);
|
|
|
+
|
|
|
+ while (rs.next()) {
|
|
|
+ int idx = 1;
|
|
|
+ String productNo = rs.getString("product_no");
|
|
|
+ Long productId = productNoToId.get(productNo);
|
|
|
+ ins.setObject(idx++, productId, Types.BIGINT); // 可能为 null
|
|
|
+ ins.setString(idx++, rs.getString("image_no"));
|
|
|
+ // 关键:通过 product_no 查 product_id
|
|
|
+ ins.setString(idx++, productNo);
|
|
|
+ ins.setString(idx++, rs.getString("image_url"));
|
|
|
+ ins.setString(idx++, rs.getString("product_details_pc"));
|
|
|
+ ins.setString(idx++, rs.getString("product_details_app"));
|
|
|
+ ins.setString(idx++, rs.getString("spec"));
|
|
|
+
|
|
|
+ // 新增字段设默认值
|
|
|
+ ins.setString(idx++, "000000"); // tenant_id
|
|
|
+ ins.setString(idx++, "0"); // status
|
|
|
+ ins.setString(idx++, "0"); // del_flag
|
|
|
+
|
|
|
+ Timestamp createdTime = rs.getTimestamp("created");
|
|
|
+ if (createdTime == null) {
|
|
|
+ createdTime = new Timestamp(System.currentTimeMillis());
|
|
|
+ }
|
|
|
+ ins.setTimestamp(idx++, createdTime);
|
|
|
+
|
|
|
+ Timestamp modifyTime = rs.getTimestamp("modify");
|
|
|
+ if (modifyTime == null) {
|
|
|
+ modifyTime = new Timestamp(System.currentTimeMillis());
|
|
|
+ }
|
|
|
+ ins.setTimestamp(idx++, modifyTime);
|
|
|
+
|
|
|
+ ins.setString(idx++, null); // platform_code(若源表无,可设 null 或固定值)
|
|
|
+
|
|
|
+ ins.addBatch();
|
|
|
+ count++;
|
|
|
+
|
|
|
+ if (count % BATCH_SIZE == 0) {
|
|
|
+ ins.executeBatch();
|
|
|
+ mysql.commit();
|
|
|
+ ins.clearBatch();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (count % BATCH_SIZE != 0) {
|
|
|
+ ins.executeBatch();
|
|
|
+ mysql.commit();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ System.out.println(Thread.currentThread().getName() + " 完成,迁移 " + count + " 条图片记录");
|
|
|
+ return count;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|