【问题标题】:How spring data clean persited entities in transactional method?spring data 如何在事务方法中清理持久化的实体?
【发布时间】:2019-01-11 12:57:58
【问题描述】:

我需要通过休眠使用 spring 数据来接收和保存大量数据。我们的服务器分配的 RAM 不足以同时保存所有实体。我们肯定会得到 OutOfMemory 错误。

所以我们需要分批保存数据,这是显而易见的。此外,我们需要使用@Transactional 来确保所有数据都持久化或非持久化,以防出现单个错误。

所以,问题是:@Transactional 方法期间的弹簧数据是否将实体存储在 RAM 中,或者垃圾收集器可以访问已刷新的实体?

那么,使用 Spring Data 处理大量数据的最佳方法是什么?也许弹簧数据不是解决此类问题的正确方法。

【问题讨论】:

  • 在您的上下文中定义“巨大”?
  • 数十万个可变大小的实体(10 kb - 2mb)
  • 就像你说的你必须做批处理。 @Transactional 与批处理没有任何直接关系。有很多方法可以插入批次。但通常为整个记录集保持事务打开是一种不好的做法。您使用什么 DBMS?
  • DB2。因此,使用 2 阶段提交 - 似乎非常危险且难以实施。
  • 在插入数十万个实体时,您真的想要全部还是全部?我的意思是使用一个总括交易?

标签: java spring hibernate spring-data transactional


【解决方案1】:

@Transactional 方法期间的弹簧数据是否会继续将实体存储在 被刷新的 RAM 或实体可被垃圾访问 收藏家?

实体将继续存储在 RAM 中(即entityManager),直到事务提交/回滚或 entityManager 被清除。这意味着实体只有在事务提交/回滚或 entityManager.clear() 被调用。

那么,处理大量数据的最佳方法是什么? 春季数据?

防止OOM的一般策略是批量加载和处理数据。在每个批次结束时,您应该刷新并清除entityManager,以便entityManager 可以为CG 释放其托管实体。一般的代码流程应该是这样的:

@Component
public class BatchProcessor {

    //Spring will ensure this entityManager is the same as the one that start transaction due to  @Transactional
    @PersistenceContext
    private EntityManager em;

    @Autowired
    private FooRepository fooRepository;

    @Transactional
    public void startProcess(){

        processBatch(1,100);
        processBatch(101,200);
        processBatch(201,300);
        //blablabla

    }

    private void processBatch(int fromFooId , int toFooId){
        List<Foo> foos =  fooRepository.findFooIdBetween(fromFooId, toFooId);
        for(Foo foo :foos){
            //process a foo
        }

        /*****************************
        The reason to flush is send the update SQL to DB . 
        Otherwise ,the update will lost if we clear the entity manager 
        afterward.
        ******************************/
        em.flush();
        em.clear();
    }
} 

请注意,这种做法只是为了防止 OOM,而不是为了实现高性能。因此,如果您不关心性能,您可以放心地使用此策略。

【讨论】:

  • 肯,谢谢你的解释!我有问题 1) 我正确理解,如果在仅一次调用 processBatch() 错误期间,整个事务将被回滚? 2)您认为最佳性能解决方案是什么?
  • @ArtyomKarnov 是的。要么全有,要么全无。要么处理所有记录,要么不处理任何记录。为了获得最佳性能,我建议直接使用 JDBC。它应该比微调 hibernate 更容易。当然,当认真谈论性能时,你最好实际测量它....
猜你喜欢
  • 2018-05-01
  • 2014-10-20
  • 2017-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-02
  • 1970-01-01
  • 2016-12-27
相关资源
最近更新 更多