Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 基于用户配置的自定义串行接口';数据库并发问题的研究_Java_Spring_Spring Boot_Jmeter_Optimistic Locking - Fatal编程技术网

Java 基于用户配置的自定义串行接口';数据库并发问题的研究

Java 基于用户配置的自定义串行接口';数据库并发问题的研究,java,spring,spring-boot,jmeter,optimistic-locking,Java,Spring,Spring Boot,Jmeter,Optimistic Locking,在我们的项目中,我们创建了一个表(即serial_conf),该表具有一些用户可以设置的配置。 当我们需要为特定实体生成序列(即28_12_2019_0001)时,我们称此序列为服务类,其上有@Transactional 该服务正在执行以下操作: 从数据库中获取当前的串行配置 使用返回的对象生成序列号 更新序列号计数器,以便下次我们可以使用递增计数器(即0002)生成正确的序列号。 将结果字符串返回给服务的调用者 现在的问题是,当我使用Jmeter对API进行压力测试时(同时10个线程)。这个A

在我们的项目中,我们创建了一个表(即serial_conf),该表具有一些用户可以设置的配置。 当我们需要为特定实体生成序列(即28_12_2019_0001)时,我们称此序列为服务类,其上有@Transactional

该服务正在执行以下操作:

  • 从数据库中获取当前的串行配置
  • 使用返回的对象生成序列号
  • 更新序列号计数器,以便下次我们可以使用递增计数器(即0002)生成正确的序列号。
  • 将结果字符串返回给服务的调用者
  • 现在的问题是,当我使用Jmeter对API进行压力测试时(同时10个线程)。这个API正在执行许多操作,其中之一就是生成序列号。 在10个线程中,只有2个或4个通过,其他线程在serial服务的步骤1上抛出OptimisticLockingFailureException

    当我尝试使用synchronized时,我读过一些文章,但没有成功。我甚至创建了一个singleton类,它使用synchronized签名调用我的服务,所有使用串行服务的API现在都调用这个singleton,这样它们就可以一个接一个地排队,但它也不起作用

    现在我的问题是:处理这个问题的正确方法是什么?我应该让数据库对表进行锁定吗?或者我应该使用不支持自定义样式的数据库序列(即28_12_2019_0001)

    (我正在使用SpringBoot1.5、hibernate和postgresql)

    编辑1: 假设服务是这样的:

    @Service("SerialService")
    @Transactional(readOnly = false)
    public class SerialService{
    
        @Autowired
        private SerialRepo repo;
    
        public String generate(Long userId){
                Serial serial = repo.findByUserId(userId).get();
                serial.setCounter(serial.getCounter() + 1);
                serial = repo.save(serial);
                return "custom_serial_"+serial.getCounter().toString();
        }
    }
    

    我想这就是正在发生的事情:

  • 线程A:进入
    generate
    方法,调用
    repo.findByUserId
    并阻塞,等待结果
  • 线程B:进入
    generate
    方法,调用
    repo.findByUserId
    并阻塞,等待结果
  • 线程A:
    repo.findByUserId
    调用完成,返回
    Serial
    ,版本为
    version
    =1
  • 线程B:
    repo.findByUserId
    调用完成,返回
    Serial
    ,版本为
    version
    =1
  • 线程A:更新计数器并保存实体。版本更新为2
  • 线程B:更新计数器并尝试保存实体。由于版本不匹配,引发OptimisticLockingFailureException
  • 同步
    generate
    方法没有帮助,因为事务是在进入该方法之前打开的(在Spring生成的代理中),所以两个线程看到相同的初始
    版本

    通常,通过重试操作来处理OptimisticLockingFailureException是很正常的,假设冲突很少发生(因此命名为“乐观锁定”)。在你的情况下,他们是相当频繁的

    问题是您的测试是否反映了实际的应用程序使用情况。我假设它们使用相同的
    用户ID执行10个并行请求。我进一步猜测,每个用户都有独立的
    Serial
    实例,因此它们的版本是独立的。这意味着,只有当一个用户同时发送两个请求时,才会抛出OptimisticLockingFailureException。这可能会发生,但我想不应该如此频繁,所以重试是可以接受的


    我建议您使用不同的用户ID重复测试。

    我想这就是发生的情况:

  • 线程A:进入
    generate
    方法,调用
    repo.findByUserId
    并阻塞,等待结果
  • 线程B:进入
    generate
    方法,调用
    repo.findByUserId
    并阻塞,等待结果
  • 线程A:
    repo.findByUserId
    调用完成,返回
    Serial
    ,版本为
    version
    =1
  • 线程B:
    repo.findByUserId
    调用完成,返回
    Serial
    ,版本为
    version
    =1
  • 线程A:更新计数器并保存实体。版本更新为2
  • 线程B:更新计数器并尝试保存实体。由于版本不匹配,引发OptimisticLockingFailureException
  • 同步
    generate
    方法没有帮助,因为事务是在进入该方法之前打开的(在Spring生成的代理中),所以两个线程看到相同的初始
    版本

    通常,通过重试操作来处理OptimisticLockingFailureException是很正常的,假设冲突很少发生(因此命名为“乐观锁定”)。在你的情况下,他们是相当频繁的

    问题是您的测试是否反映了实际的应用程序使用情况。我假设它们使用相同的
    用户ID执行10个并行请求。我进一步猜测,每个用户都有独立的
    Serial
    实例,因此它们的版本是独立的。这意味着,只有当一个用户同时发送两个请求时,才会抛出OptimisticLockingFailureException。这可能会发生,但我想不应该如此频繁,所以重试是可以接受的


    我建议您使用不同的用户ID重复您的测试。

    您能提供相关的服务代码吗?我想知道
    OptimisticLockingFailureException
    从何而来。您在
    串行
    实体中是否有
    @Version
    字段?@ma如果是,我有一个名为(长版本)的版本字段,则如果没有版本,则不会引发OptimisticLockingFailureException。您是否可以包括相关的服务代码?我想知道
    OptimisticLockingFailureException
    从何而来。在
    串行
    实体中是否有
    @Version
    字段?@m如果是,我有一个名为(长版本)的版本字段,则OptimisticLockingFailureException不会出现