I have the following code in which I must gather some data and based on certain logic, send emails.
@Transactional
public void sendReports() {
List<Execution> finishedExecutions = executionService.findAllFinishedExecutionsWithPendingReport();
for (Execution execution : finishedExecutions) {
if (!execution.anyBatchFailed()) {
execution.setReportSent(true);
continue;
}
Store store = execution.getStore();
TypeConsistency typeConsistency = execution.getTypeConsistency();
Set<StoreRecipient> recipients = storeRecipientRepository.findAllByStoreAndTypeConsistency(store, typeConsistency);
try {
LocalDateTime executionCreatedAt = execution.getCreatedAt().toLocalDateTime();
mailingService.sendMessageWithAttachment(
EmailWithAttachment.csv()
.to(recipients.stream().map(r -> r.getRecipient().getEmail()).collect(Collectors.toSet()))
.filename("foo")
.subject("bar")
.contents("My CSV Example")
.build()
);
execution.setReportSent(true);
} catch (IOException e) {
alertService.sendAlert("foo", "bar");
}
}
}
So far the code works, however, due to the nature of email sending, the transaction started by @Transactional
could potentially be left open for more than I'd like (30+ seconds if we have to send many emails). This goes against what I've read about transactions and how they should be relatively short lived.
The real reason why I'm forced to use @Transactional
here is because the Store
in Execution
and other attributes of most of the entities you see here use lazy loading. If I don't use transactions, Hibernate throws a LazyInitializationException
. So, in short, I'm forced to use transactions here in the same method that sends emails just for the sake of lazy loading things.
Is there a way to prevent this without having to resort to anti-patterns such as enable_lazy_load_no_trans
and FetchType.EAGER
?