【问题标题】:Spring synchronized method NOT SYNCHRONIZEDSpring同步方法未同步
【发布时间】:2014-04-18 04:36:54
【问题描述】:

环境:

  • apache tomcat 7

  • java 7

  • 甲骨文 11g

  • 日食

  • apache jmeter 2.1

  • 春天

  • 休眠

    我正在开发一个 Web 应用程序,它接收来自客户端的请求并根据请求类型为它们生成序列号以用于进一步处理。 为了生成唯一的序列号,我有一种方法可以从数据库中获取当前序列号并将其递增 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): [

虽然函数是同步的。

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

【问题讨论】:

    标签: hibernate tomcat spring-mvc jmeter


    【解决方案1】:

    扩展 Azizi 的答案...

    @Transactional 使 Spring 将类包装在 AOP 代理中。然后将目标方法执行包装在事务拦截器中。所以整体调用如下所示:

    -> FooProxy#generateSequenseNumber
       -> TransactionInterceptor#invoke
          -> BEGIN TRANSACTION
             -> Foo#generateSequenceNumber (synchronized)
          -> COMMIT|ROLLBACK TRANSACTION
    

    您可以(并且应该)尝试在方法中放置断点以查看堆栈中的内容。

    如果你想在generateSequenseNumber 方法中解决同步问题,那么你可以使用TransactionTemplateREQUIRES_NEW 传播。当然@Transactional注解就没有意义了。

    【讨论】:

    • 如果对答案投反对票的人会真正评论他们看到的问题,那就太好了:(。
    【解决方案2】:

    问题是@Transactional在进入同步方法之前开始会话,并在方法完成后提交更改,因此对数据库的更改不会应用到同步方法内部。

    请查看Spring @Transactional 第 10.5.1 节。

    您可以尝试在调用此方法时添加同步块而不是使其同步:

    synchronized(this){
       generateSequenseNumber();
    }
    

    【讨论】:

    • 如果您尝试从同一类中的另一个方法调用事务性方法,您的建议将不起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-15
    • 2018-07-09
    • 2011-06-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多