如何将对象存储在内存中,并在Max(数量,时间)之后将它们刷新到目标位置

问题描述 投票:0回答:2

我的Spring Boot应用程序获取输入Student,需要将其写入数据库。

我可以在获得Student对象后立即向数据库写入数据,但我想通过在内存中累积几个学生然后将大量的Students保存到数据库中来提高效率。

因此,我正在寻找一种解决方案,该解决方案能够为Max(some duration, number of students)缓存学生,并且一旦达到限制,就可以将学生批量保存。

[可以用Thread等编写代码,但似乎这个问题以前可能已经解决过。

caffeineguava库,但我仍然没有找到想要的东西。

java caching max bulkinsert
2个回答
1
投票

一般的想法是让队列中有等待刷新的对象。刷新将由2个事件触发:按计划(超出某些持续时间)和按大小(超出队列大小)。

在纯Java中,可以使用Executors.newSingleThreadScheduledExecutor()实现:

public abstract class FlushingCache<T> {

  private final Duration maxDuration;
  private final int maxSize;
  private final List<T> queue = new ArrayList<>();
  private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

  public FlushingCache(Duration maxDuration, int maxSize) {
    this.maxDuration = maxDuration;
    this.maxSize = maxSize;
    executor.scheduleWithFixedDelay(this::doFlush,
        maxDuration.getSeconds(),
        maxDuration.getSeconds(),
        TimeUnit.SECONDS);
  }

  public synchronized void enqueue(T element) {
    println("Enqueueing element " + element);
    queue.add(element);
    if (queue.size() >= maxSize) {
      doFlush();
    }
  }

  private synchronized void doFlush() {
    List<T> batch = new ArrayList<>(queue);
    println("Flushing batch " + batch);
    flush(batch);
    queue.clear();
  }

  // The login of flushing to DB will be implemented in the sub-classes
  protected abstract void flush(List<T> batch);
}

具有以下测试数据

public static void main(String[] args) {
  FlushingCache<String> studentsCache = new FlushingCache<>(Duration.ofSeconds(10), 3) {
    @Override
    protected void flush(List<String> batch) {
      println("### FLUSH TO DB " + batch);
    }
  };

  studentsCache.enqueue("1");
  studentsCache.enqueue("2");
  studentsCache.enqueue("3");

  studentsCache.enqueue("4");
}

private static void println(String message) {
  System.out.println(LocalTime.now().withNano(0).toString() + ": " + message);
}

结果是

16:07:17: Enqueueing element 1
16:07:17: Enqueueing element 2
16:07:17: Enqueueing element 3
16:07:17: Flushing batch [1, 2, 3]
16:07:17: ### FLUSH TO DB [1, 2, 3]
16:07:17: Enqueueing element 4
16:07:27: Flushing batch [4]
16:07:27: ### FLUSH TO DB [4]

当大小达到3时或每10秒将队列刷新到DB。

在Spring Boot应用程序而不是ScheduledExecutorService中,您可以使用@Scheduled

使用@EnableScheduling启用调度

@Component
public class StudentFlushingCache {

  private final List<T> queue = new ArrayList<>();

  @Value("${student.flushing-cache.max-size}")
  private final int maxSize;

  @Scheduled(
      fixedDelayString = "${student.flushing-cache.fixed-delay}",
      initialDelayString = "${student.flushing-cache.initial-delay}")
  public void flushPeriodically() {
     doFlush();
  }

  public synchronized void enqueue(T element) {
    /* ... */
  }

  private synchronized void doFlush() {
    /* ... */
  }
}

1
投票

您可以尝试这样的操作:1.创建单例班来容纳学生

public enum MyCache {
INSTANCE(new HashMap<>());

private Map<String, Student> students;

private MyCache(Map<String, Student> students) {
    this.students = students;
}...getter, setter}
  1. 创建StudentService,并添加将新Student推入缓存的方法:MyCache.INSTANCE.getStudents().push(...)

  2. 创建计划服务以保留缓存:

    @配置@EnableScheduling公共类ScheduledService {

    @ Scheduled(fixedDelay = 60 * 60 * 1000)公共无效ScheduledTask(){1.获取缓存2.检查是否达到限制(学生人数)3.坚持学生-studentRepository.saveAll(students)4.空缓存-list.clear()}}

© www.soinside.com 2019 - 2024. All rights reserved.