我已经为此苦苦挣扎了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 应用程序重现问题的人都需要:
- 马文
- 吉特
- JDK 6
- MySQL
他们可以按照以下步骤重现问题:
- git clone git@github.com:balteo/StaleObjectStateException.git
- 在 mysql 中创建一个名为 sose 的数据库模式create database sose;
- mvn test
- 瞧:BOOM!
谁能向我解释为什么在我的情况下会发生此异常以及如何更新地址实例而不会出现此异常?