compile 'io.werval:io.werval.modules.jpa:{werval-version}'
The JPA module provide a Plugin allowing easy usage of the Java Persistence API (version 2.1) thanks to EclipseLink.
Tip
|
JPA & EclipseLink Documentation
This documentation do not cover JPA nor EclipseLink itself as it is already well covered on the respective official specification and documentation. When working with JPA, you should know about JDBC too. |
If you are worried about performance, see the JPA Performance Benchmark. EclipseLink is the fastest JPA implementation.
In order to use the JPAPlugin
you must add a dependency to io.werval.modules.jpa
and register the plugin in your configuration.
When using Gradle:
compile 'io.werval:io.werval.modules.jpa:{werval-version}'
When using Maven:
<dependency>
<groupId>io.werval</groupId>
<artifactId>io.werval.modules.jpa</artifactId>
<version>{werval-version}</version>
</dependency>
And finally your application configuration:
app.plugins.enabled += jpa
Caution
|
JNDI & JDBC
The JPA module depends on both the JNDI and JDBC modules. You don’t need to depend on each one as your build system dependency manager will automatically add them to your classpath. But you need to declare both of the plugins, in order, for your application to start properly. |
Multiple Persistence Units in a single application are supported. To ease the most common usage, that is a single Persistence Unit, there’s a default one.
Each Persistence Unit needs a JDBC DataSource
. We’ll start by configuring the default one.
jdbc {
datasources.default {
driver = "org.h2.Driver"
url = "jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;MVCC=TRUE"
user = "sa"
password = "sa"
}
}
The configuration snippet above use the H2 Database Engine with an in-memory database. Of course you can use the database engine of your choice as long as you put the relevant JDBC driver in your application classpath.
Next, for JPA to be able to use the JDBC DataSource
it needs to be exposed in JNDI. That’s why we declared the JNDIPlugin above. In order to do that you only have to add a jndiName
property to the DataSource
configuration.
Here is the complete DataSource
configuration, exposed in JNDI as DefaultDS
:
jdbc {
datasources.default {
driver = "org.h2.Driver"
url = "jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;MVCC=TRUE"
user = "sa"
password = "sa"
jndiName = "DefaultDS"
}
}
Finally you must create a META-INF/persistence.xml
file declaring your Persistence Units and Entities:
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
<class>entities.User</class>
<class>entities.Post</class>
<class>entities.Comment</class>
<non-jta-data-source>DefaultDS</non-jta-data-source>
</persistence-unit>
</persistence>
When using a single Persistence Unit, it is named default
.
Here is how to get the current EntityManager
for the default Persistence Unit in a controller method:
Unresolved directive in <stdin> - include::src/test/java/io/werval/modules/jpa/DocumentationSupport.java[lines=18..22,indent=0]
Unresolved directive in <stdin> - include::src/test/java/io/werval/modules/jpa/DocumentationSupport.java[lines=26..35,indent=0]
An EntityManager
obtained in a HTTP interaction context (in a Filter or in a Controller), will be automatically closed when the HTTP interaction ends.
Here is how to get a new EntityManager
that you need to close yourself (usefull in tasks of background jobs):
Unresolved directive in <stdin> - include::src/test/java/io/werval/modules/jpa/DocumentationSupport.java[lines=39..47,indent=0]
Here is a configuration sample for two DataSource`s, a `default
one and another one named another
, respectively exposed in JNDI as DefaultDS
and AnotherDS
:
jdbc {
datasources.default {
driver = "org.h2.Driver"
url = "jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;MVCC=TRUE"
user = "sa"
password = "sa"
jndiName = "DefaultDS"
}
datasources.another {
driver = "org.h2.Driver"
url = "jdbc:h2:mem:another;DB_CLOSE_DELAY=-1;MVCC=TRUE"
user = "sa"
password = "sa"
jndiName = "AnotherDS"
}
}
And here is the relevant META-INF/persistence.xml
file:
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
<class>entities.User</class>
<class>entities.Post</class>
<class>entities.Comment</class>
<non-jta-data-source>DefaultDS</non-jta-data-source>
</persistence-unit>
<persistence-unit name="another" transaction-type="RESOURCE_LOCAL">
<class>entities.another.AnotherEntity</class>
<class>entities.another.DifferentEntity</class>
<non-jta-data-source>AnotherDS</non-jta-data-source>
</persistence-unit>
</persistence>
Here is how to get the current EntityManager
for the Persistence Unit named another
in a controller method:
Unresolved directive in <stdin> - include::src/test/java/io/werval/modules/jpa/DocumentationSupport.java[lines=18..22,indent=0]
Unresolved directive in <stdin> - include::src/test/java/io/werval/modules/jpa/DocumentationSupport.java[lines=50..59,indent=0]
Here is how to get a new EntityManager
for the Persistence Unit named another
:
Unresolved directive in <stdin> - include::src/test/java/io/werval/modules/jpa/DocumentationSupport.java[lines=63..71,indent=0]
On Application activation, all EntityManagerFactories
are created, one per Persistence Unit.
On Application passivation, all EntityManagerFactories
are closed.
In any case, calls to newEntityManager()
or newEntityManager( String pu )
will always create a new EntityManager
without holding it in a "Context Local" or a ThreadLocal
.
Transactions are not automatically opened nor closed. You need to do it, either using the JPA API, using the helper methods provided by the plugin, or by using the @JPA.Transactional
annotation.
Unresolved directive in <stdin> - include::src/test/java/io/werval/modules/jpa/Controller.java[lines=19..20,indent=0]
import io.werval.modules.jpa.JPA;
Unresolved directive in <stdin> - include::src/test/java/io/werval/modules/jpa/Controller.java[lines=23..24,indent=0]
public class AnyController
{
Unresolved directive in <stdin> - include::src/test/java/io/werval/modules/jpa/Controller.java[lines=31..47,indent=4]
}
Unresolved directive in <stdin> - include::src/test/java/io/werval/modules/jpa/Controller.java[lines=19..20,indent=0]
import io.werval.modules.jpa.JPA;
Unresolved directive in <stdin> - include::src/test/java/io/werval/modules/jpa/Controller.java[lines=23..24,indent=0]
public class AnyController
{
Unresolved directive in <stdin> - include::src/test/java/io/werval/modules/jpa/Controller.java[lines=49..67,indent=4]
}
Unresolved directive in <stdin> - include::src/test/java/io/werval/modules/jpa/Controller.java[lines=19..20,indent=0]
import io.werval.modules.jpa.JPA;
Unresolved directive in <stdin> - include::src/test/java/io/werval/modules/jpa/Controller.java[lines=23..24,indent=0]
public class AnyController
{
Unresolved directive in <stdin> - include::src/test/java/io/werval/modules/jpa/Controller.java[lines=69..76,indent=4]
}