当我在2个不同的事务中保存对象时,代码中出现以下错误:
对象乐观锁定失败异常:具有标识符[]得类[]得对象:乐观锁定失败;嵌套的异常是组织。休眠。行已被另一事务更新或删除(或未保存值Map不正确):[]
我一直在尝试为异常编写测试。但是,所有测试都已通过。
我的测试:
@Slf4j
@Rollback
@Transactional
@DataJpaTest
@ActiveProfiles({"test", "h2"})
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Import(value = {
StatusService.class
})
class StatusServiceTest {
@Autowired
private RequestRepository repository;
@Autowired
private StatusService statusService;
private Request request;
private final UUID requestUID = UUID.randomUUID();
@BeforeEach
void setUp() {
request = new Request();
request.setRequestUID(requestUID);
repository.save(request);
}
@Test
void updateStatus() {
Request request1 = repository.findByRequestUID(requestUID);
Request request2 = repository.findByRequestUID(requestUID);
statusService.updateStatus(request1, "Done");
statusService.updateStatus(request2, "In_progress");
}
}
服务项目:
@Service
@Slf4j
@RequiredArgsConstructor
public class StatusService {
private final RequestRepository repository;
@Transactional
public void updateStatus(Request request, String status) {
// Some simple logic
request.setStatus(status);
repository.save(request); // The line with error
}
}
产品型号:
@Entity
@Getter
@Setter
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Request {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@JsonIgnore
protected Long id;
protected UUID requestUID;
private String status;
// Some additional fields
@JsonIgnore
@Version
private Integer version;
}
我哪里错了?如何编写触发错误的测试?
1条答案
按热度按时间kx5bkwkv1#
@DataJpaTest
包含@Transactional
,因此您的测试会在单一交易中执行。但是对于单个事务,JPA的一级缓存可以确保对于给定的类和id,您将始终获得相同的示例。这意味着
request1
和request2
实际上是相同的示例,并且只发生一次刷新,这将不会创建乐观锁定异常。有两种方法可以创建乐观锁定异常。
1.实际上使用两个或更多事务。
TransactionTemplate
对此非常有用。您可以将request1
的加载放在第一个事务中,然后加载、修改、保存和刷新request2
,然后修改、保存和刷新request1
。如果您想让它更接近生产环境中发生的情况,您可以启动两个线程来执行这些操作,并使用CountDownLatch
确保它们继续执行以期望的顺序。1.或者,您应该能够通过加载请求、修改其版本属性并刷新事务处理来触发所需的异常。当然,这与生产中发生的情况相差甚远,但正如所述,它应该会触发异常。