Transactions in Application scoped component using Quartz timer
fridgebuzz Jan 29, 2009 3:06 PMHi,
I'm having trouble with a no transaction is in progress
exception whenever I try to flush an entity manager in a particular case (I'll explain below.)
There are two separate things going on here that could be the cause and I don't know which. The first is that I'm using an Application-scoped component, and the second is that I'm using an @Asynchronous method (a Quartz scheduled method.) Either one alone could be the problem, so I apologize if I'm confounding the two.
What I have is an Application-scoped component that starts a periodic Quartz-scheduled task to clean up un-needed records in the database.
In shortened form--with some messy details removed--the code looks something like this:
@Name("accountReaper") @Startup @Scope(ScopeType.APPLICATION) public class AccountReaper { private EntityManagerFactory emf = null; public AccountReaper() { emf = Persistence.createEntityManagerFactory("yourview"); reapInterval = reapHours * 60 * 60 * 1000; reapAccounts(new Date(), reapInterval); } @Asynchronous public QuartzTriggerHandle reapAccounts(@Expiration Date when, @IntervalDuration Long interval) { Calendar cal = Calendar.getInstance(); cal.add(Calendar.HOUR_OF_DAY, -1*timeoutHours); Date maxCreationDate = cal.getTime(); pruneUsers(maxCreationDate); return null; } @Transactional private void pruneUsers(Date maxCreationDate) { EntityManager entityManager = emf.createEntityManager(); Query query = entityManager.createQuery("select m from User m where m.creationDate < :date and m.status = :status") .setParameter("date", maxCreationDate, TemporalType.TIMESTAMP) .setParameter("status", User.UserStatusType.UNCONFIRMED); List<User> users = query.getResultList(); for (User user: users) { entityManager.remove(user); } if (!users.isEmpty()) entityManager.flush(); }
The trouble is that the flush() causes a this exception:
javax.persistence.TransactionRequiredException: no transaction is in progress
In a way it makes sense that @Transactional wouldn't work, since that applies to conversations and we're not in conversation-land here anymore (I believe.) Can anyone give me a hint about how to proceed? I don't know if it's the @Asynchronous method that's the problem or the Application-scope of the component that's the problem.
The only solution I can think of to try is to create my own transaction, with something like (leaving out the try/catch stuff for brevity):
UserTransaction transaction = Transaction.instance(); transaction.begin(); for (User user: users) { entityManager.remove(user); } if (!users.isEmpty()) entityManager.flush(); transaction.commit();
Am I on the right track? Can anyone suggest a better solution or explain the cause of the problem?
Thank you all for your attention,
Vanessa