我很感激帮助理解为什么我的应用程序找不到实体,即使它存在于数据库中;我认为这个问题与并发写作/阅读有关。我正在使用jpa2 / hibernate 4和spring 3。
我有一个创建用户的方法,然后将id作为json对象消息发送到进一步处理用户的消息队列。当消息处理程序(UserProcessor.class)尝试find
用户时出现问题(见下文)。
Registration.class
@Transactional
public Response createUser(String firstName, String lastName) {
User tmpUser = new User(firstName, lastName);
User savedUser = this.em.merge(tmpUser);
this.em.flush();
if (savedUser != null) {
processUser(savedUser.getId()); // message sent to queue.
} else {
// Throw exception...
}
}
UserProcessor.class
@Transactional(rollbackFor={javax.ws.rs.WebApplicationException.class})
public void processUser(Long id) {
User user = this.em.find(User.class, id); // No user entity is found, "user" is null.
if (user == null) {
// throw exception
}
...
}
答案 0 :(得分:1)
我认为您可能遇到并发问题。
据我了解您的代码,它的工作原理如下:
Registration.createUser:
步骤A4)提交交易(I)
UserProcessor.processUser(Long id)
步骤B1)从队列中获取用户ID
您知道(取决于您的事务隔离级别)只有在提交第一个事务(I)时,事务(I)中写入的数据才能读取其他事务(II)。
因此,如果UserProcessor.processUser在步骤A4中提交事务(I)之前尝试处理步骤B3,则它将不会在数据库中看到用户。 (如果您使用更高的事务隔离级别,那么您甚至可能需要在B2之前执行步骤A4。)
一种解决方法是切换步骤A3和A4的顺序。一个重点:如果在其他(外部)事务的上下文中调用方法Response.createUser
,那么它将使用外部事务提交!
答案 1 :(得分:0)
您可以使用两种方法:
@Transactional(rollbackFor={javax.ws.rs.WebApplicationException.class})
public void processUser(Long id) {
processUser(this.em.find(User.class, id));
}
public void processUser(User aUser) {
...
}