Spring同步方法NOT SYNCHRONIZED

时间:2014-03-13 12:30:18

标签: hibernate tomcat spring-mvc jmeter

环境:

  • apache tomcat 7
  • java 7
  • oracle 11g
  • apache jmeter 2.1
  • 弹簧
  • 休眠

    我正在开发一个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): [

虽然功能是同步的。

任何建议都会有所帮助。感谢。

2 个答案:

答案 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方法中解决同步问题,则可以使用TransactionTemplateREQUIRES_NEW传播。当然,@Transactional注释没有任何意义。