Я уже более недели борется с StaleObjectStateException
и решил опубликовать здесь простое приложение, которое воспроизводит проблему.Понимание оптимистической блокировки StaleObjectStateException
Я понимаю, что org.hibernate.StaleObjectStateException
является исключение оптимистической блокировки. Кроме того, оптимизационная блокировка основана на использовании поля версии в каждом из классов сущностей.
Теперь позвольте мне объяснить, как я воспроизвел выше исключение: пример приложение имеет класс Member
сущности, которая заключается в следующем:
@RooJavaBean
@RooToString
@RooJpaEntity
public class Member {
@OneToOne(cascade=CascadeType.ALL)
private Address address;
//id, version fields as well as mutator/accessors are located in a separate Roo ITD/aspect
}
Вот класс Address
объекта:
@RooJavaBean
@RooToString
@RooJpaEntity
public class Address {
private String formattedAddress;
private double lng;
private double lat;
//id, version fields as well as mutator/accessors are located in a separate Roo ITD/aspect
}
Использование a префикс/неуправляемый экземпляр адреса и управляемый экземпляр пользователя, я пытаюсь обновить адрес участника в ServiceImpl
класс следующим образом:
@Override
public void updateMemberAddress(Member member, Address address) {
long addressId = member.getAddress().getId();
address.setId(addressId);
updateAddress(address);
}
Вот тестовый класс:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/META-INF/spring/applicationContext*.xml")
@TransactionConfiguration(defaultRollback = false)
public class AddressIntegrationTest {
@Autowired
private Service service;
@Before
@Transactional
public void testInsertOneMember() {
Member member = new Member();
Address address = new Address();
address.setFormattedAddress("Eiffel Tower, Paris");
address.setLat(48.005);
address.setLng(3.288);
member.setAddress(address);
service.saveMember(member);
}
@Test
@Transactional
public void testUpdateAddress() {
Member member = service.findAllMembers().get(0);
Address address = new Address();
address.setFormattedAddress("Empire State Building, New York");
address.setLat(200.033);
address.setLng(36.665);
service.updateMemberAddress(member, address);
}
}
К сожалению, я получаю страшился StaleObjectStateException следующим образом:
org.springframework.orm.jpa.JpaOptimisticLockingFailureException: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [org.sose.domain.Address#1];
Любой желающий воспроизвести проблему с помощью для примера github требуется приложение:
- Maven
- Гит
- JDK 6
- MySQL
Они могут воспроизвести проблему, выполнив следующие действия:
git clone [email protected]:balteo/StaleObjectStateException.git
- В MySQL создать схему базы данных под названием sose
create database sose;
mvn test
- и voila:
BOOM
!
Может кто-нибудь объяснить мне, почему это исключение происходит в моем случае и как обновить экземпляр адреса без получения этого исключения?
Hi Johanna! Ummm ... Address также имеет определенное поле id. Он фактически расположен в отдельном файле aspectj (как и в случае с членом). Что произойдет, если я не установил идентификатор адреса, это то, что в итоге я получаю другой экземпляр Address в таблице адресов ... – balteo
И если вы задали идентификатор адреса, то у вас есть только один экземпляр в базе данных, потому что второй экземпляр не написан из-за исключения ;-). Даже с отдельным идентификатором адреса в настройке адреса идентификатор в том виде, в котором вы делаете это, - это нонсенс. Затем у вас также есть два экземпляра с одним и тем же основным ключом. В вашем заявлении «Address address = new Address();» вы явно создаете второй экземпляр адреса, и для этого нужен уникальный идентификатор. Если вам не нужен второй экземпляр адреса, вы должны это сделать: «Адрес address = member.getAddress(); address.setXXX (...); service.updateMember (member); ' – Johanna
Используя это:' Адрес address = member.getAddress(); 'Мне тогда нужно управлять/копировать поля по одному, что может быть утомительным, если есть много полей. Я хотел этого избежать. – balteo