我正在使用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:我如何为第二次(嵌套)事务配置实体管理器,以便我得到一个新交易的新鲜事。可以这样做吗?
答案 0 :(得分:-1)
我不确定您为什么会遇到报告的问题,如果您的日志代码和业务逻辑代码具有REQUIRE_NEW,则它们之间不应存在干扰。我的代码中有一个非常类似的设置。您确定交易是否在您认为的位置被触发?您使用代理交易还是AspectJ交易?
如果您正在使用代理事务,那么您必须小心通过代理来保证tx启动。
你可以做的另一件事就是使用SpringJDBC模板进行用户日志记录,让@Repository同时使用EntityManager和JDBCTemplate完全不同,只是不要在同一个方法中混合它们。