@Transactional在未提交的事务上获取旧值

时间:2014-07-11 14:57:37

标签: java spring hibernate spring-data spring-transactions

我正在编写一个@Transactional方法

  1. 更新实体(Service1.update)
  2. 在另一个进行计算的服务中调用另一个@Transactional方法(也涉及当前更新的实体)(Service2.calculate)
  3. 我的问题是,在第2点,我做了一个也涉及当前更新实体的选择。外部事务尚未提交,select选择加载旧实体值。所以微积分是基于旧的价值观。

    class Service1{
    
        @Autowired
        private Service2 service2;
    
        @Transactional(readOnly=false)
        public update(final Entry entry) {
    
            repository.save(entry);
            // already tried to flush session injecting entityManager 
            //or to call saveAndFlush, but it doesn't works!
    
            service2.calculate(entry.getContainer());
        }
    }
    
    class Service2{
    
        @Transactional(readOnly=false)
        public calculate(final Container entry) {
            //do the job: calculate the sum of the power of each entity grouper by category
            List<Report> report = calcRepository.calculate(entry);
    
            //here the report is filled with sum composed also by the of old value of current entity
    
        }
    }
    
    
    class CalcRepository extends PagingAndSortingRepository{
        @Query("select new Report(" +
                "a.type, " +
                "a.combust, "+
                "a.container.id, "+
                "sum(a.power)) "+
                "from Entry a " +
                "where ..... " +
                "group by a.type, a.combust")
        List<Report> calculate(@Param("container") Container container);
    }
    

    我正在进行选择以获取当前容器的分组值:每次修改实体时,我都必须重新计算其容器的值。

    我该如何解决这个问题?谢谢

2 个答案:

答案 0 :(得分:2)

这里发生的是:

  • 您可以修改交易中的某个实体
  • 未提交交易
  • 您需要重新计算某些依赖于此实体的报告

由于报告不是托管实体,因此Hibernate使用本机查询来获取它。这意味着它将根据数据库中的实际数据进行评估,而不是修改后的实体数据。由于您尚未提交您的交易,修改后的数据尚未在数据库中。

据我所见,您有多种选择:

  • 刷新您的交易。根据Hibernate文档判断,这应该同步数据库和实体而不提交。
  • 如果您的报告不是很复杂,您可能只想修改它以获取已更改的数据(例如,如果它是某个字段的平均值,则添加您对实体计数所做更改的差异)
  • 让您的Report成为管理实体。 (并非总是可能)
  • 使用Java而不是SQL计算报告。
  • 螺旋休眠并使用您自己的交易。然后您不需要提交读取新数据。
  • 将您的交易细分为子交易,提交每个交易。

答案 1 :(得分:2)

PropagationFlush添加到您的服务中:

class Service1 {

    @Autowired
    private Service2 service2;

    @Transactional(propagation=Propagation.REQUIRED)
    public update(final Entry entry) {

        repository.saveAndFlsuh(entry);
        // already tried to flush session injecting entityManager 
        //or to call saveAndFlush, but it doesn't works!

        service2.calculate(entry.getContainer());
    }
}

class Service2{

    @Transactional(propagation = Propagation.SUPPORTS)
    public calculate(final Container entry) {
        //do the job: calculate the sum of the power of each entity grouper by category
        List<Report> report = calcRepository.calculate(entry);

        //here the report is filled with sum composed also by the of old value of current entity

    }
}