【问题标题】:How many times Database is hit in Spring DATA JPA's save(Iterable<S> entities)在 Spring DATA JPA 保存(Iterable<S> 实体)中命中数据库多少次
【发布时间】:2018-02-07 05:37:27
【问题描述】:

我有以下几行代码:

@RequestMapping(value="/persons",method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<List<Person>> saveUsers(@RequestBody List<Person> persons) {
        persons = (List<Person>) userRepository.save(persons);
        return new ResponseEntity<List<Person>>(persons, HttpStatus.OK);
}

这里是存储库:

@Transactional
public interface UserRepository  extends UserBaseRepository<User> { 
}

@NoRepositoryBean
public interface UserBaseRepository<T extends User> extends CrudRepository<T, Long> {
    public T findByEmail(String email);
}

运行良好。运行代码时,我看到以下日志。

Hibernate: insert into user (email, firstname, lastname, user_type) values (?, ?, ?, 'Person')
Hibernate: insert into user (email, firstname, lastname, user_type) values (?, ?, ?, 'Person')
Hibernate: insert into user (email, firstname, lastname, user_type) values (?, ?, ?, 'Person')
Hibernate: insert into user (email, firstname, lastname, user_type) values (?, ?, ?, 'Person')

看来,DataBase 被命中了 4 次。我已经看到了 save(iterable e) 方法的实现,其中运行 for 循环来保存每个实体。所以,我的问题是:

  1. DB 命中了 4 次吗?
  2. 如果是这样,那么它可以在 1 db hit(使用 Spring Data JPA)中完成吗?这样做,在插入大量记录的情况下是否会提高性能?

【问题讨论】:

  • 是的,你打了 db 4 次。如果您正在使用高负载应用程序,最好使用休眠批处理或......使用多线程进行自己的批处理操作。
  • 这取决于您访问数据库 4 次的意思 - 您可能在一个连接上有 4 次插入,而真正的成本可能是创建连接
  • @farrellmr :我也这么认为。那么,上述插入记录的方案,是不是从性能上看,是否比JDBC的preparedStatement的addBatch()和executebatch()更有效呢?
  • 这取决于您期望在一批中插入多少个 - 我的意思是如果数量小于 10,我会保持原样。否则,您需要纠正自定义查询。与说 JDBC 或自定义查询的区别在于 spring-data 正在为您生成插入,因此您正在委托控制
  • 我认为,通过自定义查询,您的意思是 @Query 注释,但是,如果要插入的记录数高于 50 到 100 ?

标签: java spring hibernate spring-data-jpa


【解决方案1】:

来自the docs on Hibernate Batching

Hibernate 在 JDBC 级别透明地禁用插入批处理,如果 您使用身份标识符生成器。

因此,如果Person 使用Identity 生成器(而不是Sequence 生成器或TABLE 生成器)批处理将不会发生。请参阅this section 了解更多详情。

【讨论】:

    【解决方案2】:

    是的,您正在查询数据四次。

    您可以通过实现Hibernate Batching 在一个批处理语句中完成插入。特别是看看执行batch inserts。使用批量插入,您必须通过显式调用会话中的flush()clear() 方法来手动控制会话。

    另外,考虑设置适当的Hibernate Batching Properties,例如批处理大小(默认为 5),如果适用,允许 Hibernate 在构造批处理语句之前重新排序插入和更新:

    hibernate.jdbc.batch_size = 25
    hibernate.order_inserts = true
    hibernate.order_updates = true
    

    【讨论】:

    • 我尝试了你的建议,但结果是一样的。 final List&lt;T&gt; savedEntities = new ArrayList&lt;T&gt;(entities.size()); int i = 0; for (T t : entities) { savedEntities.add(persistOrMerge(t)); i++; if (i % batchSize == 0) { // Flush a batch of inserts and release memory. entityManager.flush(); entityManager.clear(); } } return savedEntities; } private &lt;T extends User&gt; T persistOrMerge(T t) { if (t.getId() == 0) { entityManager.persist(t); return t; } else { return entityManager.merge(t); } }
    猜你喜欢
    • 2022-01-07
    • 1970-01-01
    • 1970-01-01
    • 2019-09-30
    • 1970-01-01
    • 1970-01-01
    • 2019-11-05
    • 2014-09-25
    • 2013-05-09
    相关资源
    最近更新 更多