【发布时间】:2023-04-02 16:30:01
【问题描述】:
我有调度器:
@Component
public class MyScheduler {
private static final long INIT_DELAY = 1L;
private static final long DELAY = 10L;
private final UserService userService;
public MyScheduler(UserService userService) {
this.userService = userService;
}
@EventListener(ApplicationReadyEvent.class)
public void schedule() {
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleWithFixedDelay(this::process, INIT_DELAY, DELAY, TimeUnit.SECONDS);
}
private void process() {
userService.process(new User("Bill", 20));
}
}
在 UserService 中我保存新用户并抛出异常:
@Slf4j
@Service
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public void process(User user) {
log.info("Start process...");
userRepository.save(user);
methodWithException();
log.info("End process...");
}
private void methodWithException() {
throw new RuntimeException();
}
}
因此,尽管出现异常,用户仍被保存。为了解决这个问题,我可以应用几种方法:
1) 在private void process()上方添加@Transactional,并将此方法改为public
2) 在UserServicepublic void process(User user)方法上方添加@Transactional
在第一种情况下它没有帮助,因为 process() witn @Transactional 从同一个类调用。
在第二种情况下它会有所帮助。
但是如果我添加新的Service,例如LogService:
@Service
public class LogServiceImpl implements LogService {
private final LogRepository logRepository;
public LogServiceImpl(LogRepository logRepository) {
this.logRepository = logRepository;
}
@Transactional
@Override
public Log save(Log log) {
return logRepository.save(log);
}
}
并将调度程序更改为:
@Component
public class MyScheduler {
private static final long INIT_DELAY = 1L;
private static final long DELAY = 10L;
private final UserService userService;
private final LogService logService;
public MyScheduler(UserService userService, LogService logService) {
this.userService = userService;
this.logService = logService;
}
@EventListener(ApplicationReadyEvent.class)
public void schedule() {
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleWithFixedDelay(this::process, INIT_DELAY, DELAY, TimeUnit.SECONDS);
}
private void process() {
User user = userService.process(new User("Bill", 20));
logService.save(new Log(user.getId(), new Date()));
}
}
问题:
userService.process 调用一个事务,logService.save 调用另一个事务。我需要在一笔交易中调用双方服务。
我看到了两种方式:
1) 将logService 注入userService 并在userService.process 方法中调用logService.save
2) 使用process 方法创建新服务,例如SchedulerService,并在该服务中注入userService 和logService。并在一个事务中调用两个服务。
在第一种情况下,我在userService 中获得了新的依赖项,这可能违反了此服务的责任范围。为什么服务应该知道拉另一个服务
在第二种情况下,我需要创建额外的服务(一个类)
最好能够注释内部调度程序方法@Transactional 注释。我知道这可以使用 cglib 而不是 proxy 来完成,但我使用代理。
哪种方法更好?
【问题讨论】:
-
cglib 也是一个代理。区别一个是基于接口的另一个是基于类的,但仍然都是代理。在
process方法中使用TransactionTemplate将这两种方法包装在一个事务中。或者将process方法移动到不同的类,然后简单地将方法标记为@Transactional。 -
@ M. Deinum “或者将流程方法移动到不同的类并简单地将方法标记为@Transactional” - 这只是我的第二种情况 - “2)创建新服务,例如带有方法的 SchedulerService在此服务中处理并注入 userService 和 logService。并在一个事务中调用两个服务。"。
标签: java spring design-patterns transactions scheduled-tasks