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
相关产品推荐
相关产品推荐

