gpt4 book ai didi

hibernate - 了解乐观锁定 StaleObjectStateException

转载 作者:行者123 更新时间:2023-12-02 00:09:57 26 4
gpt4 key购买 nike

我已经为 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
  • JDK 6
  • MySQL

他们可以按照以下步骤重现问题:

  • git clone git@github.com:balteo/StaleObjectStateException.git
  • 在 mysql 中创建一个名为 sose 的数据库模式 create database sose;
  • mvn 测试
  • 瞧:BOOM!

任何人都可以向我解释为什么在我的情况下会出现此异常,以及如何在不出现此异常的情况下更新地址实例吗?

最佳答案

我在您的代码中看到两个问题:

1) 设置成员(member)地址时,不修改id,设置地址对象。 updateMemberAddress应该是这样的

@Override
public void updateMemberAddress(Member member, Address address) {
member.setAddress(address);
updateMember(member);
}

2) 成员和地址之间存在一对一的关系。我不知道您的确切数据模型,但据我所知,成员有一个 ID,而地址没有明确定义的 ID。这不是必需的,因为地址具有成员的 ID,同时它是主键(1:1 关系)。

但是,当您更改地址的 id(声明 address.setId(addressId);)时,您此时有两个地址对象(以前附加到成员的旧地址和新地址)具有相同的主键。 Hibernate 无法处理具有相同主键的两个实例。

在将新地址实例附加到此成员之前,您必须删除旧地址实例。 (更好的解决方案是添加版本号或单独的 id 来处理并将关系 member:address 更改为 1:n。)

可能是问题 2) 产生了错误。

关于hibernate - 了解乐观锁定 StaleObjectStateException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15931491/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com