并发写作&阅读JPA2 / Hibernate

时间:2012-03-01 20:42:43

标签: java spring hibernate jpa

我很感激帮助理解为什么我的应用程序找不到实体,即使它存在于数据库中;我认为这个问题与并发写作/阅读有关。我正在使用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
  }
  ...
}

2 个答案:

答案 0 :(得分:1)

我认为您可能遇到并发问题。

据我了解您的代码,它的工作原理如下:

Registration.createUser:

  • 步骤A1)打开交易(I)
  • 步骤A2)创建一个用户并将其与该事务(I)一起存储在数据库中
  • 步骤A3)将用户ID放入队列
  • 步骤A4)提交交易(I)

    UserProcessor.processUser(Long id)

  • 步骤B1)从队列中获取用户ID

  • 步骤B2)打开交易(II)
  • 步骤B3)在事务(II)
  • 中加载用户的id
  • 步骤B4)做事
  • 步骤B5)提交交易(II)

您知道(取决于您的事务隔离级别)只有在提交第一个事务(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) {
 ...
}