gpt4 book ai didi

java - 我应该将托管实体传递给需要新事务的方法吗?

转载 作者:搜寻专家 更新时间:2023-10-30 19:42:45 25 4
gpt4 key购买 nike

我的应用程序加载了应处理的实体列表。这发生在一个使用调度器的类中

@Component
class TaskScheduler {

@Autowired
private TaskRepository taskRepository;

@Autowired
private HandlingService handlingService;

@Scheduled(fixedRate = 15000)
@Transactional
public void triggerTransactionStatusChangeHandling() {
taskRepository.findByStatus(Status.OPEN).stream()
.forEach(handlingService::handle);
}
}

在我的 HandlingService 中,使用 REQUIRES_NEW 传播级别隔离处理每个任务。

@Component
class HandlingService {

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void handle(Task task) {
try {
processTask(task); // here the actual processing would take place
task.setStatus(Status.PROCCESED);
} catch (RuntimeException e) {
task.setStatus(Status.ERROR);
}
}
}

代码之所以有效,是因为我在 TaskScheduler 类上启动了父事务。如果我删除 @Transactional 注释,实体将不再受管理,并且对任务实体的更新不会传播到 db。我发现将预定方法设为事务性并不自然。

据我所知,我有两个选择:

<强>1。保持今天的代​​码。

  • 也许这只是我,这是一个正确的方法。
  • 此变体访问数据库的次数最少。

<强>2。从 Scheduler 中移除 @Transactional 注解,传递任务的 id 并在 HandlingService 中重新加载任务实体。

@Component
class HandlingService {

@Autowired
private TaskRepository taskRepository;

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void handle(Long taskId) {
Task task = taskRepository.findOne(taskId);
try {
processTask(task); // here the actual processing would take place
task.setStatus(Status.PROCCESED);
} catch (RuntimeException e) {
task.setStatus(Status.ERROR);
}
}
}
  • 有更多次访问数据库(一个额外的查询/元素)
  • 可以使用@Async执行

您能否就解决此类问题的正确方法提出您的意见,也许使用另一种我不知道的方法?

最佳答案

如果您打算在单独的事务中处理每个任务,那么您的第一种方法实际上行不通,因为所有内容都在调度程序事务结束时提交。

原因是在嵌套事务中 Task 实例基本上是分离的实体(在嵌套事务中启动的 Session 不知道这些实例)。在调度程序事务结束时,Hibernate 对托管实例执行脏检查并将更改与数据库同步。

这种方法也有很大的风险,因为如果您试图在嵌套事务中的Task 实例上访问未初始化的代理,可能会出现问题。如果您更改嵌套事务中的 Task 对象图,将嵌套事务中加载的一些其他实体实例添加到其中,则可能会出现问题(因为当控件返回到调度程序事务)。

另一方面,您的第二种方法是正确且直接的,有助于避免上述所有陷阱。只是,我会读取 ID 并提交事务(在处理任务时无需将其挂起)。实现它的最简单方法是从调度程序中删除 Transactional 注释并使存储库方法具有事务性(如果它还不是事务性的)。

如果(且仅当)第二种方法的性能是一个问题,正如您已经提到的,您可以使用异步处理,甚至在某种程度上并行处理。另外,您可能想看看 extended sessions (对话),也许您会发现它适合您的用例。

关于java - 我应该将托管实体传递给需要新事务的方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36452744/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com