环境:
休眠
我正在开发一个Web应用程序,它接收来自客户端的请求,并根据要在进一步处理中使用的请求类型为它们生成序列号。 为了生成唯一的序列号,我有一种从DB获取当前序列号并将其递增1然后按新序列号更新该记录的方法。
功能:
@Transactional
public synchronized Long generateSequenseNumber(String requestType) {
//get current sequence number for this requestType
//increment it by one
//update it in DB
}
该功能正常,但问题是当我从压力测试工具(JMeter)调用应用程序每秒发送50个请求时,我得到以下异常:
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [
虽然功能是同步的。
任何建议都会有所帮助。感谢。
答案 0 :(得分:5)
问题是@Transactional在进入synchronized方法之前开始会话并在方法完成后提交更改,因此不会在synchronized方法中应用对数据库的更改。
请查看Spring @Transactional第10.5.1节。
您可以在调用此方法时尝试添加synchronized块,而不是将其同步:
synchronized(this){
generateSequenseNumber();
}
答案 1 :(得分:1)
延伸Azizi的答案......
@Transactional
使Spring在AOP代理中包装该类。然后将目标方法执行包装在事务拦截器中。所以整体电话看起来像这样:
-> FooProxy#generateSequenseNumber
-> TransactionInterceptor#invoke
-> BEGIN TRANSACTION
-> Foo#generateSequenceNumber (synchronized)
-> COMMIT|ROLLBACK TRANSACTION
您可以(并且应该)尝试在您的方法中放置断点以查看堆栈中的内容。
如果要在generateSequenseNumber
方法中解决同步问题,则可以使用TransactionTemplate
和REQUIRES_NEW
传播。当然,@Transactional
注释没有任何意义。