1

如何在单个语句中插入所有行。这是我的代码,但插入行需要很长时间。

for(Myobject object : objectList)
        getCurrentSession().save(object);

它为每条记录创建一个语句;

insert into myobject (id, type) values (?, ?)
insert into myobject (id, type) values (?, ?)
....

我想做的是;

insert into myobject (id, type) values (?, ?), (?, ?), (?, ?) ......(?, ?);

有没有办法创建这个语句?

4

4 回答 4

3

您可能对 Hibernate 教程中的批量插入感兴趣。

问题不在于save()操作,因为所做的所有操作都是将保存的对象放入一级缓存中(在会话中,使其持久化),而是flush()触发插入的操作。他们推荐以下方法以获得良好的性能

在教程中也说过 - 我没有尝试过 - 你可以获得OutOfMemoryException非常多的持久行,并且它们似乎推荐20作为批量大小。

当使新对象持久化时 flush() 然后 clear() 定期会话以控制一级缓存的大小。

for ( int i=0; i<objectList.size(); i++ ) {
   getCurrentSession().save(objectList.get(i));
   if ( i % 20 == 0 ) { //20, same as the JDBC batch size
    //flush a batch of inserts and release memory:
   session.flush();
   session.clear();
   }
}

EDIT也可以hibernate.jdbc.batch_size在配置文件中设置为 20。如果需要,也可以设置为 50。Hibernate 必须将它们分组,而不是 20 个插入,您应该只有一个按 20 分组:

into myobject (id, type) values (id1, val1), (id2, val2), ......(id20, val20)
于 2013-10-04T07:12:13.747 回答
2

我想添加一种我设法使用Native Queries. 我从@Bohemian 的回答中获得了一些灵感。首先,在服务层,我们将对象列表拆分为块,然后在DAO层,我们插入每个块。

服务

@Override
public void massInsert(List<Object> objects) throws Exception {

    // First, let's split the list in chunks.
    final int chunkSize = 50;
    final AtomicInteger counter = new AtomicInteger();
    final Collection<List<Object>> result =
            objects.stream().collect(Collectors.groupingBy(it -> counter.getAndIncrement() / chunkSize)).values();

    // Now, for each iteration, we will insert the corresponding details.
    for (List<Objects> oList : result) {
        this.dao.massInsert(oList);
    }
}

@Override
public void massInsert(List<Object> objects) throws Exception {
    Session session = this.sessionFactory.getCurrentSession();

    // Create the query. It is important to consider that we will be using a
    // native query, which we will build from scratch. This is done in order to improve the insert speed.
    String hql = "insert into TABLE (column1, column2) VALUES ";

    // For each object, add a new object to insert.
    // In the end we will need to remove the last comma.
    for (int i = 0; i < objects.size(); i++) {
        hql = hql.concat("(?, ?),");
    }
    hql = hql.substring(0, hql.length()-1);

    // Create the query.
    Query query = session.createSQLQuery(hql);

    // Now, for each object, set the needed parameters.
    int index = 1;
    for (Object o : objects) {
        query.setParameter(index++, o.getAttribute1());
        query.setParameter(index++, o.getAttribute2());
    }

    // Execute the query.
    query.executeUpdate();

}

它比逐行插入要快得多。希望能帮助到你。

于 2020-02-21T00:54:10.303 回答
1

使用本机查询(原始 SQL):

entityManager
  .createNativeQuery("insert into myobject (id, type) values (?, ?), (?, ?), (?, ?) ......(?, ?)")
  .setParameter(1, foo)
  // etc
  .execute();
于 2013-10-04T07:09:21.757 回答
0

只需为休眠启用“调试”级别日志记录,然后查看是否正在发生批量插入。

  log4j.rootLogger=TRACE, file, stdout

  log4j.logger.org.hibernate=TRACE

  log4j.logger.org.hibernate.type=ALL

您应该会看到如下所示的日志。

  DEBUG AbstractBatcher:66 - Executing batch size: 20

您看到的插入语句是在调用 ps.executeBatch() 之前生成的。org.hibernate.jdbc.BatchingBatcher 的第 70 行。

于 2013-10-23T14:17:02.117 回答