java—在spring存储库中保存什么更快?

3qpi33ja  于 2021-07-13  发布在  Java
关注(0)|答案(3)|浏览(383)

我需要保存一个大约2500000大小的列表。什么更快?

repository.saveAll(list);

list.parallelStream().foreach(e -> repository.save(e));
46qrfjad

46qrfjad1#

saveall()方法会更快。saveall还遍历列表并调用save方法,因此我们可能认为性能必须相似。但是@transactional的默认传播类型是必需的,因此如果没有提供,每次都会创建一个新的事务。在saveall中只有一个事务,但在save中它将等于列表的大小。因此两者之间的性能差距。

t8e9dugd

t8e9dugd2#

受你问题的启发,我做了一个小实验。它能在10秒内把10万张唱片放到我的机器上。如果你想的话,你可以使用代码。

class Person {
  public int number;
  public String name;
}

class Cannon extends Thread {
  private Collection<Person> people;
  private int COUNT = 5000;
  public Cannon(Collection<Person> input) {
    people = input;
  }
  public void run() {
    try {
      var db = DriverManager.getConnection("jdbc:postgresql://localhost/postgres", "postgres", "test");
      var builder = new StringBuilder();
      builder.append("insert into person (name, number) values (?,?)");
      for (int i = 1; i < COUNT; i++) {
        builder.append(",(?,?)");
      }
      var s = db.prepareStatement(builder.toString());
      int i = 0;
      for (Person p : people) {
        s.setString(2 * i + 1, p.name);
        s.setInt(2 * i + 2, p.number);
        i++;
        if (i == COUNT) {
          s.executeUpdate();
          i = 0;
        }
      }
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
}

public class Main {

  static public void main(String[] args) throws InterruptedException {
    var data = new ArrayList<Person>();
    var r = new Random();
    for (int i = 0; i < 10000000; i++) {
      var p = new Person();
      p.name = String.valueOf(r.nextInt());
      p.number = r.nextInt();
      data.add(p);
    }

    var threads = new Thread[4];
    for (int i = 0; i < threads.length; i++) {
      var chunk = new ArrayList<Person>();
      for (int j = 0; j < data.size() / threads.length; j++) {
        int index = (data.size() / threads.length) * i + j;
        chunk.add(data.get(index));
      }
      threads[i] = new Cannon(chunk);
    }

    long start = System.currentTimeMillis();

    for (int i = 0; i < threads.length; i++) threads[i].start();
    for (int i = 0; i < threads.length; i++) threads[i].join();

    System.out.println(System.currentTimeMillis() - start);
  }

}
ubby3x7f

ubby3x7f3#

对spring存储库的每次调用通常以对数据库的一次调用结束。即使数据库运行在同一台主机上,它仍然是一个昂贵的操作(相对于在jvm中调用函数)。
这么叫 repository.saveAll(list) 将在一次对数据库的调用中结束 list.parallelStream().foreach(e -> repository.save(e)) 将在对列表中的每个项目的数据库调用中结束。
即使您的数据库可以同时处理多个请求,它仍然受限于主机的资源,并且可能受到dbms的同步机制的限制。换句话说,数据库一次也只能处理这么多请求。
此外,您不想在一次通话中保存250万个条目。这可能会导致outofmemoryexceptions。

相关问题