Hibernate: How to catch exception if transaction fails?

345 views
Skip to first unread message

Aditya Prasad

unread,
Aug 21, 2020, 6:01:17 PM8/21/20
to dropwizard-user
Hi,

It seems that @UnitOfWork can only be applied to resource methods. This means that if the transaction fails, there's nowhere for me to catch whatever exception is thrown (because it's DW that's invoking my method). This gives me no control over what I return to users.

What's the proper way to fix this? One thing I've tried is creating the session and transaction explicitly:

try (Session session = fooDao.factory.openSession()) {
  Transaction transaction = session.beginTransaction();
  fooDao.doStuff();
  transaction.commit();
} catch (Exception e) {
  ... error handling
}

But then in fooDao I get org.hibernate.HibernateException: No session currently bound to execution context. This probably relates to the last question I asked in the group, where `session` is valid but `sessionFactory.getCurrentSession` does not return it for some reason. What am I missing?

Thanks,
A

Dimas Guardado

unread,
Aug 23, 2020, 10:41:49 AM8/23/20
to dropwizard-user
Hi Aditya,

I can see a few options here:

1) Register an ExceptionMapper to customize the response for exceptions of a given type: https://www.dropwizard.io/en/latest/manual/core.html#error-handling
2) Add `@UnitOfWork` to a method in an object below the resource layer (eg in a Service object) and catch exceptions in the resource method that calls it. To do this, you'll need to create your service object using a `UnitOfWorkAwareProxyFactory` https://www.dropwizard.io/en/latest/manual/hibernate.html#transactional-resource-methods-outside-jersey-resources
3) Manually manage the transaction. I think if you use `getCurrentSession()` instead of creating your own session, it should work as you expect. I'd definitely recommend one of the approaches above over managing transactions yourself, though.

Do any of these work for you?

Aditya Prasad

unread,
Aug 23, 2020, 8:45:25 PM8/23/20
to dropwiz...@googlegroups.com
Excellent, thanks. (1) isn't great for me, because there isn't enough information in the exception to return what I want. (2) doesn't quite work either: my Resource methods are responsible for mapping db objects to my API objects. It would help if the session is still active there, so that any lazy fields can still be fetched.

The other major problem I see with @UnitOfWork on Resource methods is that, because the exceptions are thrown outside my code, none of my code shows up in the stack trace, making debugging much harder.
--
You received this message because you are subscribed to the Google Groups "dropwizard-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dropwizard-us...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dropwizard-user/4a254110-884f-4e42-9cf9-793efb728ec3n%40googlegroups.com.

Aditya Prasad

unread,
Aug 23, 2020, 9:05:14 PM8/23/20
to dropwiz...@googlegroups.com
And now I remember: I already tried option (3). 

If I try to create a transaction while there's a @UnitOfWork annotation, I get java.lang.IllegalStateException: Transaction already active. If I try without that annotation, it fails (expectedly) with org.hibernate.HibernateException: No session currently bound to execution context. 

Thanks to your response on the other thread, I realized I have to do this:

try (Session session = fooDao.factory.openSession()) {
  ManagedSessionContext.bind(session);
  Transaction transaction = session.beginTransaction();
  fooDao.doStuff();
  transaction.commit();
  ManagedSessionContext.unbind(serviceDao.factory);
} catch (Exception e) {
  ... error handling
}

Which is pretty terrible. I might create my own annotation to create and bind/unbind the session (to use on Resource methods), and then create the transactions myself in the Service methods.

Aditya Prasad

unread,
Aug 24, 2020, 12:35:33 PM8/24/20
to dropwiz...@googlegroups.com
Ah, another option: I can annotate the Resource method with @UnitOfWork(transactional=false), and then manage just the transaction part myself.
Reply all
Reply to author
Forward
0 new messages