两个JPA EntityManager与Spring托管交易?

时间:2012-10-31 10:00:36

标签: spring hibernate jpa transactions spring-transactions

我正在使用Spring的事务支持和JPA(Hibernate)来保留我的实体。一切正常,但我在一个请求中处理部分更新时遇到困难:

对于每个用户(HTTP)请求,我都要将日志条目写入数据库表,即使“主”业务实体的更新失败(例如由于验证错误)。所以我的第一个/主要事务得到回滚,但第二个(写日志)应该提交。这似乎可以使用正确的传播级别来写入日志条目:

@Repository
@Transactional(propagation = Propagation.REQUIRES_NEW)
public class UserTracker extends ... {

  @PersistenceContext private EntityManager em;

  public void log(...) {
    // create log entity and persist it
    ...
    em.persist(log);
    em.flush();
  }

}

然而,我的问题是,我在第二个事务中注入了与第一个事务中相同的EntityManager。因此,刷新实体管理器(在第二个事务提交时显式或隐式)也将从第一个事务中清除我的脏业务实体。

我该如何解决这个问题?我想使用第二个,干净和新鲜的EntityManager作为日志记录部分,我知道我可以通过编程方式打开一个,但是有一个更干净/声明的“Spring-way”这样做吗?

修改

我的问题可能源于这样一个事实,即我的第二笔交易嵌套在我的主要业务交易中:

|-------------- A --------------X   <- Rollback of main business transaction (A)
                    |--- B ---|     <- Commit of second log transaction (B)

我已经解决了序列化这两笔交易的问题:

|--------- A --------X |--- B ---|

所以现在一切都很好,但出于好奇:如果我坚持第一种方法而不是按照建议采用JDBC:我如何为第二次(嵌套)事务配置实体管理器,以便我得到一个新交易的新鲜事。可以这样做吗?

1 个答案:

答案 0 :(得分:-1)

我不确定您为什么会遇到报告的问题,如果您的日志代码和业务逻辑代码具有REQUIRE_NEW,则它们之间不应存在干扰。我的代码中有一个非常类似的设置。您确定交易是否在您认为的位置被触发?您使用代理交易还是AspectJ交易?

如果您正在使用代理事务,那么您必须小心通过代理来保证tx启动。

你可以做的另一件事就是使用SpringJDBC模板进行用户日志记录,让@Repository同时使用EntityManager和JDBCTemplate完全不同,只是不要在同一个方法中混合它们。