0

我正在使用 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:我将如何为第二个(嵌套)事务配置实体管理器,以便我得到一个新的新的交易。这可以做到吗?

4

1 回答 1

-1

我不确定您为什么遇到您报告的问题,如果您的日志记录代码和业务逻辑代码具有 REQUIRE_NEW 则它们之间应该没有干扰。我的代码中有一个非常相似的设置。你确定交易是在你认为的地方触发的吗?你使用的是代理交易还是aspectJ交易?

如果您使用代理交易,那么您必须小心通过代理以确保 tx 启动。

您可以做的另一件事是使用 SpringJDBC 模板进行用户日志记录,让 @Repository 使用 EntityManager 和 JDBCTemplate 做一些事情是非常好的,只是不要将它们混合在同一个方法中。

于 2012-10-31T14:07:55.993 回答