hibernate
Hibernate ORM enables developers to more easily write applications whose data outlives the application process. As an Object/Relational Mapping (ORM) framework, Hibernate is concerned with data persistence as it applies to relational databases.
This module setup and configure Hibernate ORM and JPA Provider
.
NOTE: This module depends on jdbc module.
exports
- SessionFactory / EntityManagerFactory
- Session / EntityManager
- UnitOfWork
dependency
<dependency>
<groupId>org.jooby</groupId>
<artifactId>jooby-hbm</artifactId>
<version>1.6.6</version>
</dependency>
usage
{
use(new Jdbc());
use(new Hbm()
.classes(Beer.class));
get("/api/beer/", req -> {
return require(UnitOfWork.class).apply(em -> {
return em.createQuery("from Beer").getResultList();
});
});
}
unit of work
We provide an UnitOfWork to simplify the amount of code required to interact within the database.
For example the next line:
{
require(UnitOfWork.class).apply(em -> {
return em.createQuery("from Beer").getResultList();
});
}
Is the same as:
{
Session session = require(SessionFactory.class).openSession();
Transaction trx = session.getTransaction();
try {
trx.begin();
List<Beer> beers = em.createQuery("from Beer").getResultList();
trx.commit();
} catch (Exception ex) {
trx.rollback();
} finally {
session.close();
}
}
An UnitOfWork takes care of transactions and session life-cycle. It’s worth to mention too that a first requested UnitOfWork bind the Session
to the current request. If later in the execution flow an UnitOfWork, Session
and/or EntityManager
is required then the one that belong to the current request (first requested) will be provided it.
open session in view
We provide an advanced and recommended Open Session in View pattern, which basically keep the Session
opened until the view is rendered, but it uses two database transactions:
-
first transaction is committed before rendering the view and then
-
a read only transaction is opened for rendering the view
Here is an example on how to setup the open session in view filter:
{
use(new Jdbc());
use(new Hbm());
use("*", Hbm.openSessionInView());
}
event listeners
JPA event listeners are provided by Guice, which means you can inject dependencies into your event listeners:
@Entity
@EntityListeners({BeerListener.class})
public class Beer {
}
public class BeerListener {
@Inject
public BeerListener(DependencyA depA) {
this.depA = depA;
}
@PostLoad
public void postLoad(Beer beer) {
this.depA.complementBeer(beer);
}
}
Hibernate event listeners are supported too via onEvent(EventType, Class):
{
use(new Hbm()
.onEvent(EventType.POST_LOAD, MyPostLoadListener.class));
}
Again, MyPostLoadListener
will be provided by Guice.
persistent classes
Persistent classes must be provided at application startup time via classes(Class…):
{
use(new Jdbc());
use(new Hbm()
.classes(Entity1.class, Entity2.class, ..., )
);
}
Or via scan
:
{
use(new Jdbc());
use(new Hbm()
.scan()
);
}
Which scan
the application package defined by hibernate.packagesToScan
property, or you can provide where to look:
{
use(new Jdbc());
use(new Hbm()
.scan("foo.bar", "x.y.z")
);
}
advanced configuration
Advanced configuration is provided via doWithXXX
callbacks:
{
use(new Hbm()
.doWithBootstrap(bsrb -> {
// do with bsrb
})
.doWithRegistry(ssrb -> {
// do with ssrb
})
);
}
Or via hibernate.*
property from your .conf
file:
hibernate.hbm2ddl.auto = update
life-cycle
You are free to inject a SessionFactory
or EntityManagerFactory
and create a new EntityManagerFactory#createEntityManager()
, start transactions and do everything you need.
For the time being, this doesn’t work for a Session
or EntityManager
. A Session
and/or EntityManager
is bound to the current request, which means you can’t freely access from every single thread (like manually started thread, started by an executor service, quartz, etc…).
Another restriction, is the access from Singleton
services. If you need access from a singleton services, you need to inject a Provider
.
@Singleton
public class MySingleton {
@Inject
public MySingleton(Provider<EntityManager> em) {
this.em = em;
}
}
Still, we strongly recommend to leave your services in the default scope and avoid Singleton
objects, except of course for really expensive resources. This is also recommend approach by Guice.
Services in the default scope won’t have this problem and are free to inject the Session
or EntityManager
directly.
hbm.conf
These are the default properties for hbm:
hibernate.session_factory_name_is_jndi = false
hibernate.archive.autodetection = class
hibernate.current_session_context_class = managed
hibernate.packagesToScan = ${application.ns}