2

I have a method that is going to call a stored function. I want it to async'ly do its work. This is what I have, but it seems like the .doWork() is never started because when I call getDao.deleteAll(), the stored function does not run.

@Transactional
    public void delete()
    {

        final Session session = (Session) entityManager.getDelegate();
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.execute(new Runnable()
        {
            @Override
            public void run()
            {
                LOGGER.warn("starting");
                session.doWork(new Work()
                {
                    @Override
                    public void execute(Connection connection) throws SQLException
                    {
                        try
                        {

                            CallableStatement purgeArchived = connection.prepareCall("{call deleteAll()}");
                            purgeArchived.execute();
                        }
                        catch (SQLException exception)
                        {
                            LOGGER.warn("Failed to purge archive points. Reason: " + exception);
                        }
                    }
                });
                LOGGER.warn("stopping");
            }
        });
        executorService.shutdown();
    }

I see the logger has logged "starting", but it never got to "stopping" why is this happening?

PhoonOne
  • 2,678
  • 12
  • 48
  • 76
  • Try moving `final Session session = (Session) entityManager.getDelegate();` inside the `run` method as well. – Luiggi Mendoza Nov 21 '14 at 16:53
  • just tried that, no luck – PhoonOne Nov 21 '14 at 17:11
  • Try using `while (!executorService.isTerminated()) { }` after `executorService.shutdown();`. This will make the current thread wait until the thread(s) in `ExecutorService` have finished. This is for testing purposes because if it ends here it means that the problem is in the main thread that initializes this thread. – Luiggi Mendoza Nov 21 '14 at 19:30
  • The problem is at: CallableStatement purgeArchived = connection.prepareCall("{call deleteAll()}"); I put logging statement behind that, nothing after prepareCall gets logged. Not sure why.. – PhoonOne Nov 21 '14 at 19:51
  • Seems like the connection is being closed while the other thread is still working. This is the kind of problems you encounter when managing your threads and a external thread manages the opening and close of the connections. – Luiggi Mendoza Nov 21 '14 at 19:55
  • that sounds like what is happening here.. – PhoonOne Nov 21 '14 at 19:59
  • Are you integrating Hibernate with Spring or something else to manage the connection opening/closing? – Luiggi Mendoza Nov 21 '14 at 20:00
  • Using hibernate with Spring. – PhoonOne Nov 21 '14 at 20:04

1 Answers1

2

Be aware that @Transaction is moot when you have a separate thread as Transactions are typically thread bound.

You will need to get a new entityManager from the factory inside the run().

Also go for @Async which is much cleaner.

Again be aware of transactionality with @Async

@Async and @Transactional: not working

As a general rule of thumb if you want to make some work async - treat that as a single unit of work and a separate transaction.

Community
  • 1
  • 1
bhantol
  • 9,368
  • 7
  • 44
  • 81
  • so currently my DAO is extending a GenericDAOJpa which in there, it creates the entity manager. So you are saying I should create a new one inside the run()? @bhantol – PhoonOne Nov 24 '14 at 14:01
  • Adding a new entityManager did work! but can you tell me the reason behind it? Thanks @bhantol – PhoonOne Nov 24 '14 at 15:28
  • Also are you suggesting that to use @Async instead of @Transactional? or use both? – PhoonOne Nov 24 '14 at 15:30
  • 1
    @JennyC EntityManagers are not thread safe. https://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/transactions.html The reason why adding getting EntityManager inside the run() worked is that it was able to get a fresh entityManager in that thread versus using the entityManager created in parent/another thread. – bhantol Nov 24 '14 at 17:58
  • 1
    Yes annotate `@Async` and `@Transnational` on the same method. (transaction is isolated) – bhantol Nov 24 '14 at 18:06