EntityManager.clear()不会停止将数据写入数据库

时间:2017-07-13 15:20:13

标签: java spring hibernate jpa

我遇到一种情况,用户需要将一个有价值数据的文件导入数据库。他们可以在开始时选择是否执行标准导入,然后创建报告摘要文件,或“模拟”导入(即创建相同的报告摘要,但实际上不导入任何内容)。基本设置如下:

public class Importer {

  @Autowired
  protected IConverter converter;
  @Autowired
  protected ISerializer serializer;
  @Autowired
  protected IReporter reporter;  


  public void import( InputStream stream ) throws Exception {
    CustomerData data = converter.convert( stream ); 
    // ** database at this point has been updated! **
    if( getContext().isSerialize() ) {
       serializer.serialize( data );
    }
    if( getContext().isReport() ) {
       reporter.report( data, "report.xls" );
    }
  }
}

public class Converter implements IConverter throws Exception {
  @Transactional
  public CustomerData convert( InputStream stream ) {
    try {
      CustomerData data = ... // read file and create/match with db entities
      return data;
    } finally {
      if( !getContext().isSerialize() ) {
        // clear any changes made to objects made in the db
        getEntityManager().clear();
        // ** database at this point is unaffected **
      }
    }
  }
}

Importer是在Spring 4.1中配置的bean类。数据库是JPA 2.1 / Hibernate 4.3.11 / MySQL 5.5。使用Java 8。

CustomerData对象是一个数据库实体对象树,其中一些已与数据库中的数据匹配(可能使用导入文件中的数据更新属性)以及其他新成员。

isSerialize()和isReport()允许控制数据库是否更新。模拟导入时,isSerialize()= false,isReport()= true。

单步执行代码,当我输入finally块并清除实体管理器时,数据库中的数据就像导入之前一样。但是当我返回到import()方法时,数据库已经根据实体的更改进行了更新!

显然,事务性import()方法完成提交数据,但为什么清除实体管理器不会阻止更改发生?为了确保我在[Hibernate] AbstractEntityManagerImpl.flush()上设置一个断点,这里根本没有调用它。

有人可以帮助我理解为什么clear()不起作用,以及我应该做什么。

1 个答案:

答案 0 :(得分:0)

谢谢,S. Piller让我走上正轨。对于处于类似位置的任何人,清除实体管理器不会停止在事务结束时提交给数据库的刷新更改 - clear()将仅清除自上次刷新以来更改的实体。

解决方法是通知事务管理器需要回滚事务:

  @Transactional
  public CustomerData convert( InputStream stream ) {
    try {
      CustomerData data = ... // read file and create/match with db entities
      return data;
    } finally {
      if( !getContext().isSerialize() ) {
        // Ensure the current transaction is rolled back once the topmost @Transactional method completes.
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      }
    }
  }