I'm facing a problem with Spring Data JPA insert. I've a scheduler that runs after a week. It selects n records from a source table based on certain criteria and then check if a target table, x, exists. If not, the table is created and the selected data inserted. The data that were successfully inserted into the target table are deleted from the source table.
@Component
public class ArchiveService {
// Some dependencies here!!!
@Transactional
public int archiveSmsEntries(Month month, Year year) {
// ...
this.createNewTable(suffix);
// ...
// LocalDateTime start;
// LocalDateTime end;
int size = 200;
boolean running = true;
while (running) {
Page<SmsEntry> entries = smsService.findAllForArchiving(start, end, PageRequest.of(0, size, Sort.Direction.ASC, "created"));
result += this.saveAndDelete(entries.getContent());
running = entries.getTotalElements() > 0;
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createNewTable(String suffix) {
if (repo.tableExists(ArchiverUtils.table + suffix)) {
log.warn("Archive already exists.");
} else {
Session session = em.unwrap(Session.class);
session.doWork(connection -> {
//// ...
// Create table
//// ...
});
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int saveAndDelete(List<SmsEntry> entries) {
if (entries.isEmpty())
return 0;
AtomicInteger r = new AtomicInteger(0);
try {
Session session = em.unwrap(Session.class);
session.doWork(connection -> {
boolean autoCommit = connection.getAutoCommit();
connection.setAutoCommit(true);
PreparedStatement ps = connection.prepareStatement("INSERT STATEMENT");
for (SmsEntry entry : entries) {
ps.setInt(1, entry.getId());
ps.setDouble(2, entry.getCost());
ps.addBatch();
}
r.set(Arrays.stream(ps.executeBatch()).sum());
if (r.get() > 0) {
entryService.deleteAllById(entries.stream().map(SmsEntry::getId).collect(Collectors.toList()));
}
ps.close();
connection.setAutoCommit(autoCommit);
});
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return r.get();
}
}
The above runs well immediately when called, but after a while, it throws this exception:
org.springframework.dao.InvalidDataAccessApiUsageException: No transactional EntityManager available; nested exception is java.lang.IllegalStateException: No transactional EntityManager available
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:371)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:257)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
...
So I do not really know why this was thrown and how to solve it. I saw similar question online like Spring - PersistenceContext - No transactional EntityManager available and No transactional EntityManager available Error. My main task was to get 200 records, manipulate and save immediately (commit to DB immediately). I'll be extremely grateful for any assistance. Thanks.