Java Spring保存记录并发送消息回滚

Java Spring保存记录并发送消息回滚,java,spring,spring-data,Java,Spring,Spring Data,我有一门课: @Service @Transactional class MyService{ @Autowired MyTableRepository repository; @Autowired FacebookMessageSender sender; public void updateTableAndSendMessage(MyTable m){ m.setProcessed(1); repository.save(m); sen

我有一门课:

@Service
@Transactional
class MyService{
   @Autowired MyTableRepository repository;
   @Autowired FacebookMessageSender sender;

   public void updateTableAndSendMessage(MyTable m){
      m.setProcessed(1);
      repository.save(m);
      sender.sendMessageToFacebook(m);
   }
}
代码中的某个地方:

List<MyTable> list=repository.findByProcessed(0);
for(MyTable m:list){
   myService.process(m);
}
List List=repository.findByProcessed(0);
用于(MyTable m:列表){
myService.process(m);
}
因此,我有以下几点:
在quartz作业中,我检索已处理标志设置为0的所有记录。然后我将其传递给服务,然后处理标志变为1,系统将消息发送到Facebook messenger(无论在何处)。但,若在“process”方法执行之前或之后发生sql异常,则事务将回滚,且标志仍为0。所以Facebook的消息将在下一次招聘会上一次又一次地发送。我尝试将它分解为两种方法,一种保存标志,另一种发送消息。但如果消息未发送,我将不得不回滚事务,该怎么办?这就像是僵局。我需要防止在其他异常时发送FB消息,并在FB发送失败时回滚DB更改。如何在spring数据中做到这一点,afaik事务将在方法结束后提交。谢谢

以下代码结构应该可以工作:

服务

调用类


解释 A.如果无法保存任务,请确保未尝试发送Facebook消息 如果无法保存单个任务,将引发异常,代码将跳过尝试为该任务发送Facebook消息的部分。因此,由于代码的结构方式,可以自动满足此要求

B确保发送Facebook消息时出错会回滚任务 行
catch(Throwable t){throw new RuntimeException(t);}
确保在保存任务或发送Facebook消息时,如果抛出任何异常(包括从
exception
而不是
RuntimeException
)时,它将作为
RuntimeException
重新抛出。这反过来将确保围绕该方法的
@Transactional
注释将回滚数据库事务

C确保处理任务时出现的错误不会影响其他任务 每个任务都在其自己的事务中处理(
@Transactional(propagation=propagation.REQUIRES_NEW)
),因此任何在错误发生之前提交的任务都将保持提交状态


当错误发生时,调用代码将捕获它(
catch(RuntimeException e)
),这样错误就不会出现在调用方的事务处理程序中,并且允许调用方根据需要尝试和处理剩余的任务。没有此catch子句意味着服务中引发的第一个
RuntimeException
也将冒泡到调用方,并将立即终止整个操作,可能会留下未处理的任务。此时不要重新抛出捕获到的异常,这一点很重要,因为重新抛出它会使异常冒泡,从而首先破坏使用catch子句的目的。

谢谢,但这不会起作用,因为在TaskService方法存储库中。save(task);将在sendTaskNotification方法退出后提交,但届时facebook消息将已发送。这就是为什么它如此棘手。Thanks@avalon,这不是你想要的吗?要么两个步骤都执行,要么一个都不执行?
@Service
class TaskService {
  @Autowired TaskRepository        repository;
  @Autowired FacebookMessageSender sender;

  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void sendTaskNotification(Task task){
    try {
      task.setProcessed(1);
      repository.save(task);

      sender.sendMessageToFacebook(task);
    }
    catch (Throwable t) {
      throw new RuntimeException(t);
    }
  }
}
@Component
class TaskNotificationJob {
  @Autowired TaskService service;

  @Scheduled
  @Transactional
  public void sendTaskNotifications() {
    for(Task task : repository.findByProcessed(0)) {
      try {
        service.sendTaskNotification(task);
      }
      catch (RuntimeException e) {
        // Log the error, but don't rethrow the exception.
      }
    }
  }
}