You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot Repository如何缓存实体至指定数量后批量存入数据库

SpringBoot 批量数据库日志记录实现方案

一、本地缓存 + JPA saveAll 批量提交

这是贴合Spring Data JPA生态的方案,利用内存缓存攒够指定数量后批量入库,同时解决主键问题:

  • 用线程安全容器(比如ConcurrentLinkedQueue)缓存日志对象,设置批量阈值(比如100条)
  • 每次生成日志时先加入缓存,达到阈值后调用saveAll()批量插入,JPA会自动为自增主键回填ID;如果业务需要提前使用ID,直接在创建日志对象时赋值UUID这类可预生成的主键
  • 加上@PreDestroy注解,在应用关闭时自动清空缓存,避免日志丢失
@Component
public class BatchLogHandler {
    private static final int BATCH_THRESHOLD = 100;
    private final ConcurrentLinkedQueue<SysLog> logCache = new ConcurrentLinkedQueue<>();
    private final SysLogRepository logRepo;

    // 构造注入Repository
    public BatchLogHandler(SysLogRepository logRepo) {
        this.logRepo = logRepo;
    }

    public void recordLog(SysLog log) {
        // 若用UUID主键,直接在这里赋值
        // log.setId(UUID.randomUUID().toString());
        logCache.add(log);
        if (logCache.size() >= BATCH_THRESHOLD) {
            flushLogs();
        }
    }

    // 手动触发或应用销毁时调用,清空缓存
    @PreDestroy
    public void flushLogs() {
        if (!logCache.isEmpty()) {
            List<SysLog> batchLogs = new ArrayList<>(logCache);
            logRepo.saveAll(batchLogs);
            logCache.clear();
        }
    }
}

二、JdbcTemplate 高效批量插入

如果对性能要求更高,直接用JdbcTemplate手写批量SQL,避免JPA的ORM开销:

  • 用同步List缓存日志,达到阈值后调用batchUpdate()执行批量插入
  • 自增主键如果需要获取,可通过KeyHolder实现;不需要的话直接忽略,专注提升插入效率
@Component
public class BatchLogHandler {
    private static final int BATCH_THRESHOLD = 100;
    private final List<SysLog> logCache = Collections.synchronizedList(new ArrayList<>());
    private final JdbcTemplate jdbcTemplate;

    public BatchLogHandler(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public void recordLog(SysLog log) {
        logCache.add(log);
        if (logCache.size() >= BATCH_THRESHOLD) {
            batchInsert();
        }
    }

    @PreDestroy
    public void batchInsert() {
        if (logCache.isEmpty()) return;

        String insertSql = "INSERT INTO sys_log (content, log_level, create_time) VALUES (?, ?, ?)";
        jdbcTemplate.batchUpdate(insertSql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int index) throws SQLException {
                SysLog log = logCache.get(index);
                ps.setString(1, log.getContent());
                ps.setString(2, log.getLogLevel());
                ps.setTimestamp(3, Timestamp.valueOf(log.getCreateTime()));
            }

            @Override
            public int getBatchSize() {
                return logCache.size();
            }
        });
        logCache.clear();
    }
}

三、之前踩坑的问题解决

  • 重写Repository的save()报错:Spring Data JPA自定义Repository需要严格遵循命名规则(比如自定义接口LogRepositoryCustom,实现类LogRepositoryImpl),且没必要重写save,直接用saveAll()更简单,避免Bean注入错误
  • 主键混乱问题:如果用自增主键,缓存阶段不要依赖ID(因为ID在入库后才生成);如果业务必须提前用ID,切换为UUID这类可预生成的主键策略,创建日志对象时直接赋值

内容的提问来源于stack exchange,提问作者Kreuzzes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 03:08:17