I have scheduller:
@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));
}
}
In UserService I save new user and throw exception:
@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();
}
}
As a result, the user is saved despite the exception. To fix this I can apply several ways:
1) Add @Transactional
above private void process()
and change this method to public
2) Add @Transactional
above public void process(User user)
method in UserService
In first case it not helps because process() witn @Transactional
calls from the same class.
In second case it helps.
But if I add new Service, for example 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);
}
}
And change scheduler to:
@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()));
}
}
Question:
userService.process
call in one transaction and logService.save
cals in another transaction. I need call bouth services in One transaction.
I see two ways:
1) inject logService
to userService
and call logService.save
in userService.process
method
2) Create new service for example SchedulerService
with method process
and inject userService
and logService
in this service. And call in bouth services in one transaction.
In first case I get new dependency in userService
and this can violate area of responsibility in this service. Why should the service know to pull another service
In second case I need create additional service (one more class)
It would be ideal to be able to annotate the internal Schedulers method @Transactional
annotation. I know that this can be done using cglib instead proxy but I use proxy.
Which approach would be better?
Aucun commentaire:
Enregistrer un commentaire