我已经和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
}使用新/非托管地址实例和托管成员实例,我试图按以下方式更新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应用程序再现问题的人都需要:
它们可以通过以下步骤再现问题:
git clone git@github.com:balteo/StaleObjectStateException.gitcreate database sose;的数据库模式mvn testBOOM!请任何人向我解释为什么在我的情况下会出现这个异常,以及如何在没有得到这个异常的情况下更新地址实例?
发布于 2013-04-11 13:14:36
我在您的代码中看到了两个问题:
1)当设置成员的地址时,不应修改id,而应设置address对象。updateMemberAddress应该是这样的
@Override
public void updateMemberAddress(Member member, Address address) {
member.setAddress(address);
updateMember(member);
}2)会员和地址之间有一对一的关系。我不知道您的确切数据模型,但据我所见,成员有一个id,而address没有显式定义的id。这是不必要的,因为address有成员的id,同时它是主键(1:1关系)。
但是,当您更改地址id (语句address.setId(addressId);)时,此时有两个地址对象(以前附加到成员的旧地址和新地址)具有相同的主键。Hibernate不能使用相同的主键处理两个实例。
在将新地址实例附加到该成员之前,必须删除旧地址实例。(一个更好的解决方案是添加版本号或单独的id,以寻址关系成员: address为1:n)。
可能是问题2)产生错误。
https://stackoverflow.com/questions/15931491
复制相似问题