Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.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 如何对单个事务多次调用@Transactional方法_Java_Spring Boot_Server - Fatal编程技术网

Java 如何对单个事务多次调用@Transactional方法

Java 如何对单个事务多次调用@Transactional方法,java,spring-boot,server,Java,Spring Boot,Server,我有办法 @Transactional public void updateSharedStateByCommunity(List[]idList) 此方法是从以下REST API调用的: @RequestMapping(method = RequestMethod.POST) public ret_type updateUser(param) { // call updateSharedStateByCommunity } 现在ID列表非常大,比如200000,当我尝试处理它时,会花费

我有办法

@Transactional
public void updateSharedStateByCommunity(List[]idList)
此方法是从以下REST API调用的:

@RequestMapping(method = RequestMethod.POST)
public ret_type updateUser(param) {
  // call updateSharedStateByCommunity
}
现在ID列表非常大,比如200000,当我尝试处理它时,会花费很多时间,并且在客户端发生超时错误

所以,我想把它分成两个电话,每个电话的列表大小为100000

但是,问题是,它被视为两个独立的交易

注意:这两个呼叫就是一个例子,如果号码ID更大,它可以被分成很多次

我需要确保对单个事务进行两次单独调用。如果两个调用中的任何一个失败,那么它应该回滚到所有操作


此外,在客户端,我们需要显示进度对话框,因此我不能只使用超时。

事务性注释(尽管并非所有底层实现都支持它)。我反对尝试将ID分成两个调用,而是尝试修复超时(毕竟,您真正想要的是单个、全部或无事务)。您可以设置超时,而不是基于每个方法。

事务注释(尽管并非所有底层实现都支持它)。我反对尝试将ID分成两个调用,而是尝试修复超时(毕竟,您真正想要的是单个、全部或无事务)。您可以设置超时,而不是基于每个方法设置超时。

在这些场景中,我首选的方法是使调用异步(Spring Boot允许使用
@Async
注释进行此操作),因此客户端不会期望任何HTTP响应。通知可以通过WebSocket完成,WebSocket将向客户端推送消息,其中包含每个X项处理的进度


当然,这会增加应用程序的复杂性,但如果您正确设计该机制,您将能够将其重新用于将来可能面临的任何其他类似操作。

在这些场景中,我首选的方法是使调用异步(Spring Boot允许使用
@Async
注释进行此操作),因此,客户机不会期望任何HTTP响应。通知可以通过WebSocket完成,WebSocket将向客户端推送消息,其中包含每个X项处理的进度


当然,这会增加应用程序的复杂性,但如果您正确设计该机制,您将能够将其重新用于将来可能面临的任何其他类似操作。

从技术角度来看,可以使用
org.springframework.transaction.annotation.Propagation#嵌套的
传播,嵌套行为使嵌套的Spring事务使用相同的物理事务,但在嵌套调用之间设置保存点,因此内部事务也可以独立于外部事务回滚,或者让它们传播。但是限制仅适用于
org.springframework.jdbc.datasource.DataSourceTransactionManager
datasource


但是对于非常大的数据集,它仍然需要更多的时间来处理并让客户端等待,因此从解决方案的角度来看,使用异步方法可能会更好,但这取决于您的需求。

从技术角度来看,这可以通过
org.springframework.transaction.annotation.Propagation#NESTED
Propagation完成,嵌套行为使嵌套的Spring事务使用相同的物理事务,但在嵌套调用之间设置保存点,因此内部事务也可以独立于外部事务回滚,或者让它们传播。但是限制仅适用于
org.springframework.jdbc.datasource.DataSourceTransactionManager
datasource


但是对于非常大的数据集,它仍然需要更多的时间来处理并让客户端等待,因此从解决方案的角度来看,使用异步方法可能会更好,但这取决于您的需求。

对于您的问题,IMO最明显的直接答案是稍微更改代码:

@RequestMapping(method = RequestMethod.POST)
public ret_type updateUser(param) {
    updateSharedStateByCommunityBlocks(resolveIds);
}

...

And in Service introduce a new method (if you can't change the code of the service provide an intermediate class that you'll call from controller with the following functionality):

@Transactional
public updateSharedStatedByCommunityBlocks(resolveIds) {
    List<String> [] blocks = split(resolveIds, 100000);  // 100000 - bulk size
    for(List<String> block :blocks) {
       updateSharedStateByCommunity(block); 
    }
}
@RequestMapping(method=RequestMethod.POST)
公共ret_类型更新程序(参数){
更新SharedStateBycomunityBlocks(ResolveId);
}
...
并且在服务中引入一个新方法(如果您不能更改服务的代码,请提供一个中间类,您将使用以下功能从控制器调用该类):
@交易的
公共更新SharedStatedByCommunityBlock(ResolveId){
List[]blocks=split(resolveIds,100000);//100000-批量大小
用于(列表块:块){
更新SharedStateBycomunity(块);
}
}
如果此方法在同一服务中,则原始
更新SharedStateBycomunity
中的
@Transactional
将不会执行任何操作,因此它将工作。如果将此代码放入其他类中,那么它将工作,因为spring事务的默认传播级别为“必需”

因此,它解决了苛刻的要求:您希望有一个单一的交易-您已经得到了。现在所有代码都在同一事务中运行。现在每个方法都使用100000个ID运行,而不是所有ID,所有内容都是同步的:)

然而,由于许多不同的原因,这种设计存在问题

  • 它不允许跟踪进度(向用户显示),正如您在问题的最后一句中所述。REST是同步的

  • 它假设网络是可靠的,等待30分钟从技术上讲不是问题(让用户体验和“紧张”的用户不得不等待:)

  • 除此之外,网络设备还可以强制关闭连接(如具有预先配置的请求超时的负载平衡器)

  • 这就是为什么人们建议某种异步流

    我可以说,您仍然可以使用异步流,生成任务,并在每次批量更新之后更新一些共享状态(对于单个实例,在内存中)和持久状态(对于集群,就像数据库)