§Integrating with JPA
§Adding dependencies to your project
First you need to tell Play that your project depends on javaJpa
which will provide JDBC and JPA api dependencies.
There is no built-in JPA implementation in Play; you can choose any available implementation. For example, to use Hibernate, just add the following dependency to your project:
libraryDependencies ++= Seq(
javaJpa,
"org.hibernate" % "hibernate-entitymanager" % "5.1.0.Final" // replace by your jpa implementation
)
§Exposing the datasource through JNDI
JPA requires the datasource to be accessible via JNDI. You can expose any Play-managed datasource via JNDI by adding this configuration in conf/application.conf
:
db.default.jndiName=DefaultDS
See the Java Database docs for more information about how to configure your datasource.
§Creating a Persistence Unit
Next you have to create a proper persistence.xml
JPA configuration file. Put it into the conf/META-INF
directory, so it will be properly added to your classpath.
Here is a sample configuration file to use with Hibernate:
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="defaultPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<non-jta-data-source>DefaultDS</non-jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
</properties>
</persistence-unit>
</persistence>
Finally you have to tell Play, which persistent unit should be used by your JPA provider. This is done by the jpa.default
property in your conf/application.conf
.
jpa.default=defaultPersistenceUnit
§Deploying Play with JPA
Running Play in development mode while using JPA will work fine, but in order to deploy the application you will need to add this to your build.sbt
file.
PlayKeys.externalizeResources := false
Note: Since Play 2.4 the contents of the
conf
directory are added to the classpath by default. This option will disable that behavior and allow a JPA application to be deployed. The content of conf directory will still be available in the classpath due to it being included in the application’s jar file.
§Annotating JPA actions with @Transactional
Every JPA call must be done in a transaction so, to enable JPA for a particular action, annotate it with @play.db.jpa.Transactional
. This will compose your action method with a JPA Action
that manages the transaction for you:
import play.db.jpa.Transactional;
@Transactional
public Result index() {
return ok("A Transactional action");
}
If your action runs only queries, you can set the readOnly
attribute to true
:
@Transactional(readOnly = true)
public Result list() {
return ok("A Transactional action");
}
§Using play.db.jpa.JPAApi
Play offers you a convenient API to work with Entity Manager and Transactions. This API is defined by play.db.jpa.JPAApi
, which can be injected at other objects like the code below:
@Inject
public JPAController(JPAApi api) {
this.jpaApi = api;
}
If you already are in a transactional context (because you have annotated your action with @Transactional
),
public void upadateSomething() {
EntityManager em = jpaApi.em();
// do something with the entity manager, per instance
// save, update or query model objects.
}
But if you do not annotate your action with @Transactional
and are trying to access a Entity Manager using jpaApi.em()
, you will get the following error:
java.lang.RuntimeException: No EntityManager found in the context. Try to annotate your action method with @play.db.jpa.Transactional
§Running transactions decoupled from requests
It is likely that you need to run transactions that are not coupled with requests, for instance, transactions executed inside a scheduled job. JPAApi has some methods that enable you to do so. The following methods are available to execute arbitrary code inside a JPA transaction:
JPAApi.withTransaction(Function<EntityManager, T>)
JPAApi.withTransaction(String, Function<EntityManager, T>)
JPAApi.withTransaction(String, boolean, Function<EntityManager, T>)
JPAApi.withTransaction(Supplier<T>)
JPAApi.withTransaction(Runnable)
JPAApi.withTransaction(String, boolean, Supplier<T>)
§Examples:
Using JPAApi.withTransaction(Function<EntityManager, T>)
:
// lambda is an instance of Function<EntityManager, Long>
jpaApi.withTransaction(entityManager -> {
Query query = entityManager.createNativeQuery("select max(age) from people");
return (Long) query.getSingleResult();
});
Using JPAApi.withTransaction(Runnable)
to run a batch update:
// lambda is an instance of Runnable
jpaApi.withTransaction(() -> {
EntityManager em = jpaApi.em();
Query query = em.createNativeQuery("update people set active = 1 where age > 18");
query.executeUpdate();
});
§Enabling Play database evolutions
Read Evolutions to find out what Play database evolutions are useful for, and follow the setup instructions for using it.
Next: Using Ebean ORM
Found an error in this documentation? The source code for this page can be found here. After reading the documentation guidelines, please feel free to contribute a pull request. Have questions or advice to share? Go to our community forums to start a conversation with the community.