Java 基于用户配置的自定义串行接口';数据库并发问题的研究
在我们的项目中,我们创建了一个表(即serial_conf),该表具有一些用户可以设置的配置。 当我们需要为特定实体生成序列(即28_12_2019_0001)时,我们称此序列为服务类,其上有@Transactional 该服务正在执行以下操作: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
@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();
}
}
我想这就是正在发生的事情:
generate
方法,调用repo.findByUserId
并阻塞,等待结果generate
方法,调用repo.findByUserId
并阻塞,等待结果repo.findByUserId
调用完成,返回Serial
,版本为version
=1repo.findByUserId
调用完成,返回Serial
,版本为version
=1李>
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不会出现