Предположим, что у меня есть entity bean AccountBean с полем версии (javax.persistence.Version аннотация). Во время транзакции мое приложение изменяет этот объект и выполняет операции с базой данных на других объектах (вставляет и обновляет строки). Некоторые из этих объектов beans имеют поле @Version, но не все из них.Сделка не полностью откатывается после всплытия сервера OptimisticLockException
Когда один и тот же объект AccountBean изменяется одновременно на 2 потока, генерируется исключение OptimistickLockException и (по крайней мере, согласно журналу сервера) транзакция откатывается назад. Тем не менее, только изменения, внесенные в конфликтующий объект AccountBean, фактически откатываются - все остальное привязано к базе данных.
** EDIT: ** Я добавил простой исходный код, чтобы осветить проблему; Приложение является веб-службой REST; В двух тестовых потоках одновременно выполняется «обновление» с тем же идентификатором учетной записи. Опять же, OLE выбрасывается, и, тем не менее, предположительно откатанная транзакция фиксирует базу данных нового объекта AccountHistory:/ Так как транзакции управляются контейнером, транзакция запускается при вызове обновления метода и выполняется при его возврате; Это также когда бросается OLE.
//UpdateAccount.java
@Stateless
@Path("account")
public class UpdateAccount {
@PersistenceContext
EntityManager em;
@Path("update")
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public String update(Long accountId) {
Account account = em.find(Account.class, accountId);
if(null == account) {
return "account not found";
} else {
return executeUpdate(account);
}
}
String executeUpdate(Account account) {
Integer newValue = account.getValue() + 1;
em.persist(getAccountHistory(account, newValue));
account.setValue(newValue);
return "ok";
}
AccountHistory getAccountHistory(Account account, Integer newValue) {
AccountHistory history = new AccountHistory();
history.setId(new Date().getTime());
history.setAccount(account);
history.setValueBefore(account.getValue());
history.setValueAfter(newValue);
return history;
}
}
//Account.java
@Entity
public class Account {
@Id
private Long id;
@Column
private Integer value;
@Version
private Long version;
(...)//getters, setters etc
}
//AccountHistory.java
@Entity
public class AccountHistory {
@Id
private Long id;
@Column
private Integer valueBefore;
@Column
private Integer valueAfter;
@ManyToOne
@JoinColumn(name = "idaccount")
private Account account;
(...)//getters, setters etc
}
- Am Я неправильно ожидать, что все изменения откатываются?
- Могу ли я вручную принудительно выполнить полный откат? Я попытался вручную управлять транзакцией, ловил OLE и откатывал вызов (как описано в Adam Bien's blog). Однако, когда я поймаю исключение, транзакция равна , уже отмеченной как откат.
Я развертываю приложение на jboss-eap-6.1/jboss-as-7.1.1Final с JRE 1.7 и использую Hibernate (значения по умолчанию для этих серверов). Мой файл persistence.xml так же прост, как и он. Я не задал никаких дополнительных свойств.
Вы совершаете обе операции? Когда они запускаются в коде? Если бы вы могли добавить код, в котором запускаются транзакции, это поможет ответить. – andriosr
Привет, спасибо за ваш ответ. Я добавил простой тестовый код, чтобы проиллюстрировать проблему. После одновременного вызова обновления дважды я заканчиваю двумя новыми строками в таблице AccountHistory ... – Nexus42