Java 注意事项

本篇文章 编写规定,以问题描述为标题 ,下方附带解决方法以及处理时间/代码图片/关键词/相关url
标题须采用## ,提供代码段,相关图例

1.针对表数据同步至另一张表,存在则update、不存在则insert

老办法 (废弃):
>> 通过对目标表数据进行主键一一查询判断

缺点:

性能方面:

频繁查询与操作:在代码里,针对查询结果集中的每条记录,都会单独执行一次查询来判断记录是否存在,接着再执行插入或者更新操作。当数据量较大时,会产生大量的数据库交互,这会显著降低性能,同时增加数据库的负载。
缺乏批量操作:代码没有运用批量插入或者批量更新的功能。批量操作可以减少与数据库的交互次数,从而提升性能。例如,在 MySQL 中可以使用 INSERT INTO ... ON DUPLICATE KEY UPDATE 语句来实现批量的 “存在则更新,不存在则插入” 操作。

       // 通过 Db 获取数据库连接(Hutool 管理连接,避免泄漏)
        try (Connection conn = Db.use().getConnection()) {
            // 1. 查询源表数据(手动使用 PreparedStatement)
            String selectSql = "SELECT id, rname, money FROM HZMY_LOG  where id =2";
            try (PreparedStatement selectStmt = conn.prepareStatement(selectSql)) {
                try (ResultSet rs = selectStmt.executeQuery()) {
                    // 2. 遍历源表数据
                    while (rs.next()) {
                        int id = rs.getInt("id");
                        String name = rs.getString("rname");
                        int age = rs.getInt("money");
                        // 3. 检查目标表是否存在该记录
                        String checkSql = "SELECT id FROM HZMY_LOG_copy1 WHERE id = ?";
                        try (PreparedStatement checkStmt = conn.prepareStatement(checkSql)) {
                            checkStmt.setInt(1, id);
                            try (ResultSet checkRs = checkStmt.executeQuery()) {
                                if (checkRs.next()) {
                                    // 存在则更新
                                    String updateSql = "UPDATE HZMY_LOG_copy1 SET rname = ?, money = ? WHERE id = ?";
                                    try (PreparedStatement updateStmt = conn.prepareStatement(updateSql)) {
                                        updateStmt.setString(1, name);
                                        updateStmt.setInt(2, age);
                                        updateStmt.setInt(3, id);
                                        updateStmt.executeUpdate();
                                    }
                                } else {
                                    // 不存在则插入
                                    String insertSql = "INSERT INTO HZMY_LOG_copy1 (id, rname, money) VALUES (?, ?, ?)";
                                    try (PreparedStatement insertStmt = conn.prepareStatement(insertSql)) {
                                        insertStmt.setInt(1, id);
                                        insertStmt.setString(2, name);
                                        insertStmt.setInt(3, age);
                                        insertStmt.executeUpdate();
                                    }
                                }
                            }
                        }
                    }
                }
            }
            System.out.println("所有记录处理完成");
        } catch (SQLException e) {
            System.err.println("数据库操作失败:" + e.getMessage());
            e.printStackTrace();
        }

MERGE INTO 进行完成此需求

优点

批量操作:MERGE INTO 可以在单个事务中完成多个操作,这对于大量数据的插入、更新或删除非常有用。这通常比分别执行 INSERT、UPDATE 和 DELETE 语句要快得多,因为这样可以减少数据库的锁定和日志开销。

MERGE INTO MID_ORG_Job AS target
USING (
    SELECT
        a.OId AS ID,
        a.name AS NAME,
        a.Code AS CODE,
        a.order_emp AS SORT,
        NULL AS UNITID,
        a.Status AS IS_ENABLE,
        a.stdIsDeleted AS IS_DELETED,
        a.ModifiedTime AS UPDATE_TIME 
    FROM BeiSenJob a
    WHERE a.stdIsDeleted = '0' AND a.Status = '1'
) AS source
ON target.ID = source.ID
WHEN MATCHED THEN
    UPDATE SET
        target.NAME = source.NAME,
        target.CODE = source.CODE,
        target.SORT = source.SORT,
        target.UNITID = source.UNITID,
        target.IS_ENABLE = source.IS_ENABLE,
        target.IS_DELETED = source.IS_DELETED,
        target.UPDATE_TIME = source.UPDATE_TIME
WHEN NOT MATCHED BY TARGET THEN
    INSERT (ID, NAME, CODE, SORT, UNITID, IS_ENABLE, IS_DELETED, UPDATE_TIME)
    VALUES (
        source.ID, source.NAME, source.CODE, source.SORT,
        source.UNITID, source.IS_ENABLE, source.IS_DELETED, source.UPDATE_TIME
    );

2.sql内容过多?如何优化处理?

使用sql文件进行内容管理,可创建resources/sql/*.sql 文件,在项目中进行读取使用

.main{
  String mergeSql = loadSql("sync_job.sql");
}


    private String loadSql(String filename) {
        try {
            ClassPathResource resource = new ClassPathResource(SQL_PATH + filename);
            return StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
        } catch (IOException e) {
            logger.error("加载 SQL 文件失败:{}", filename, e);
            throw new RuntimeException("无法加载 SQL 文件:" + filename, e);
        }
    }

3.定时任务数量太多?yml通用管理

使用yml配置文件进行统一管理,例如当有很多的定时任务时

@Component
public class PersonSyncTask {
    //使用yml 进行批量管理 使用yml路径内容进行
    @Scheduled(cron = "${cron.sync.person}")
    public void sync() {
        String mergeSql = loadSql("sync_person.sql");
        executeMerge("MIDXXX同步", mergeSql);
    }
} 

在application.yml中添加

#MID同步任务 定时区域
cron:
  sync:
    person: "0 25 */1 * * ?"
    unit: "0 26 */1 * * ?"
    post: "0 27 */1 * * ?"
    department: "0 28 */1 * * ?"
    job: "0 29 */1 * * ?"

同时还可使用 封装执行器为统一接口或抽象类

public interface DataSyncTask {
    void sync();
}

增加开关控制与重试机制(可选)

feature:
  sync:
    enable-person: true
    enable-unit: true
    retry-count: 3

在任务中判断是否启用:

@Value("${feature.sync.enable-person}")
private boolean enablePersonSync;

@Scheduled(cron = "...") 
public void syncPerson() {
    if (!enablePersonSync) return;
    ...
}```