Параллельное написание и чтение с JPA2 / Hibernate - PullRequest
1 голос
/ 02 марта 2012

Буду признателен за помощь в понимании того, почему моему приложению не удается найти сущность, даже если она существует в базе данных;Я считаю, что проблема связана с одновременным написанием / чтением.Я использую jpa2 / hibernate 4 и spring 3.

У меня есть метод, который создает пользователя, а затем отправляет идентификатор, как объектное сообщение 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 ]

1 голос
/ 02 марта 2012

Я думаю, что у вас может быть проблема с параллелизмом.

Насколько я понимаю ваш код, он работает так:

Registration.createUser:

  • Шаг А1) открывает транзакцию (I)
  • Шаг А2) создать пользователя и сохранить его с этой транзакцией (I) в базе данных
  • Шаг A3) помещает идентификатор пользователя в очередь
  • Шаг A4) фиксирует транзакцию (I)

    UserProcessor.processUser (Long id)

  • Шаг B1) получает идентификатор пользователя из очереди

  • Шаг B2) открывает транзакцию (II)
  • Шаг B3) загрузить пользователя по его идентификатору в транзакции (II)
  • Шаг B4) делать вещи
  • Шаг B5) фиксация транзакции (II)

Вы знаете (в зависимости от уровня изоляции транзакции) данные, записанные в транзакции (I), могут считываться в другой транзакции (II), только если зафиксирована первая транзакция (I).

Таким образом, если UserProcessor.processUser попытается обработать шаг B3 до того, как транзакция (I) будет зафиксирована на шаге A4, он не увидит пользователя в базе данных. (Если вы используете более высокие уровни изоляции транзакций, чем вам может понадобиться выполнить шаг А4 до В2.)

Одним из обходных путей будет переключение порядка шагов A3 и A4. Один важный момент: если там метод Response.createUser вызывается в контексте другой (внешней) транзакции, то он будет зафиксирован с внешней транзакцией!

0 голосов
/ 02 марта 2012

Вы можете использовать два метода:

@Transactional(rollbackFor={javax.ws.rs.WebApplicationException.class})
public void processUser(Long id) { 
   processUser(this.em.find(User.class, id)); 
}

public void processUser(User aUser) {
 ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...