Using Spring Data JPA
Spring Data JPA is included in the Spring Framework as a framework for database access. As the name suggests, it uses JPA for data access. This article explains its basic usage.
Spring Data JPA and pom.xml
Database-related development is one of the areas with the widest range of libraries and frameworks. ORM, or Object Relational Mapping, such as Hibernate is widely used as a technology for keeping database access through SQL and Java object code consistent.
Among those ORM-related technologies, JPA, or Java Persistence API, has become the standard Java technology. Strictly speaking, JPA itself feels less like an ORM technology and more like a way to use SQL easily in a Java style, but it is used by many frameworks as a basic technology for mediating between databases and Java objects.
The Spring Framework includes a library called Spring Data JPA, which accesses databases through JPA. It is one of the database access libraries grouped under Spring Data. Other libraries are also available, such as Spring Data MongoDB for non-SQL MongoDB and Spring Data Hadoop for Hadoop. Spring Data JPA is for using relational databases based on ordinary SQL, so it can be considered the basic Spring Data library.
Now let’s use Spring Data JPA. First, add the library to pom.xml. Rewrite the source code as follows. In this example, the versions are aligned with Spring Framework 4.1.7.
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.samples</groupId>
<artifactId>MySpringApp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.6</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<!-- Database (H2) -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.187</version>
</dependency>
<!-- JPA Provider (Hibernate) -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.10.Final</version>
</dependency>
<!-- Spring Data JPA -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.8.1.RELEASE</version>
</dependency>
</dependencies>
</project>
This time, three new <dependency> tags were added. Each is briefly described below.
H2
The group ID is com.h2database, and the artifact ID is h2. H2 is a Java SQL database engine. It can store data by directly accessing database files. When you think of ordinary databases, MySQL or PostgreSQL may come to mind. A database engine such as H2, implemented as a Java library, does not require troublesome tasks such as installing a database server, so it is easy to use and well suited for learning. In this example, H2 is used as the database for Spring Data JPA.
Hibernate EntityManager
In JPA, database data is converted into objects called entities. The entity manager manages these entities. There are several options, and you can choose one that is easy to use and configure it. This example uses the entity manager created by Hibernate. Specify org.hibernate as the group ID and hibernate-entitymanager as the artifact ID.
Spring Data JPA
This is the main Spring Data JPA library. Specify org.springframework.data as the group ID and spring-data-jpa as the artifact ID.
By adding these three libraries to pom.xml, Spring Data JPA can be used. Of course, H2 is not required if you use another database server.
Create persistence.xml
First, let’s use Spring Data JPA with a bean configuration file.
To use Spring Data JPA, there are several things to prepare in the project. One of them is a file named persistence.xml. This file contains information called a persistence unit.
JPA provides persistence for executing database access. In other words, you can think of persistence.xml as the place where information about the database to access is written.
Save this file in the META-INF folder of the web application. In a Maven project, the resources folder under src/main is the web application directory. Create a META-INF folder in this resources folder, create a file named persistence.xml inside it, and write the following content.
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
<persistence-unit name="persistence-unit"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.diarect" value="${hibernate.dialect}" />
<property name="hibernate.hbm2ddl.auto" value="${hibernate.hbm2ddl.auto}" />
<property name="javax.persistence.jdbc.driver" value="${db.driver}" />
<property name="javax.persistence.jdbc.url" value="${db.url}" />
<property name="javax.persistence.jdbc.user" value="${db.user}" />
<property name="javax.persistence.jdbc.password" value="${db.password}" />
</properties>
</persistence-unit>
</persistence>
In this persistence.xml, place a <persistence-unit> tag inside the <persistence> tag. This tag describes persistence unit information. Inside it, the <provider> tag specifies the provider class, and the <properties> tag describes the required information as properties. The properties written here are as follows.
hibernate.diarect
hibernate.hbm2ddl.auto
These are required by HibernatePersistence. The dialect is the class that interacts with the database, and these settings control database processing at startup and shutdown. Here, the dialect for using H2 is configured, along with settings to prepare a new database at startup and delete it at shutdown.
javax.persistence.jdbc.driver
javax.persistence.jdbc.url
javax.persistence.jdbc.user
javax.persistence.jdbc.password
These configure the database driver, access URL, username, password, and so on.
The available properties may differ somewhat depending on the entity manager you use. This example uses the Hibernate library, so Hibernate-specific values are added as properties. If you use another entity manager, you may need to use different properties.
Create application.properties
If you look at the generated persistence.xml, the values of the properties included in the <property> tags are written in the form ${XX}. This means the values included in a properties file are inserted and used.
Create a properties file named application.properties in the project’s resources folder. Write the values required by persitence.xml here. Create it with the following content.
# Database Configuration
db.driver=org.h2.Driver
db.url=jdbc:h2:mem:datajpa
db.username=sa
db.password=
# Hibernate Configuration
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.hbm2ddl.auto=create-drop
Here, entries such as db.XX and hibernate.XX are written. Entries that start with db are basic settings for database access. They include the database driver, the URL to access the class, username, and password.
When accessing H2, specify the driver class org.h2.Driver. The access URL is jdbc:h2:mem:datajpa. This means a database named datajpa is prepared in H2 memory. Because it is created in memory, the database disappears cleanly after the program ends. This is ideal for learning.
If you want to store it as a file on the hard disk instead of in memory, write it in the form jdbc:h2:path. For example, writing jdbc:h2:/db/dbdata creates a file named dbdata in the db folder on disk and stores the data there.
For Hibernate, org.hibernate.dialect.H2Dialect is specified as the dialect value. This is the dialect class for H2. Also, create-drop is specified for hibernate.hbm2ddl.auto, which means the database is created when the program starts and deleted when it ends. In this example, the data is stored in H2 memory, so regardless of this setting, the database is deleted when the program ends.
Create the Bean Configuration File
The next thing to prepare is the bean configuration file. When using Spring Data JPA, database access is performed through an entity manager. To create it, you need to add an entity manager factory bean in the configuration file.
Create a new file named dbbean.xml in the resources folder. Then write the following content.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<jdbc:embedded-database id="dataSource" type="H2" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
</bean>
</property>
</bean>
</beans>
This time, several attributes are added to the <beans> tag to use JPA and JDBC tags. Two bean configuration tags are prepared here.
-
<jdbc:embedded-database>: This represents the database information, or data source, object. The ID is specified asdataSource, which is the ID used by the entity manager factory to use this bean. Also,type="H2"indicates that H2 is used as the database. -
<bean id="entityManagerFactory">: This defines the entity manager factory bean. Specify the classLocalContainerEntityManagerFactoryBeanfrom theorg.springframework.orm.jpapackage. The following properties can be used.- dataSource: Specifies the bean prepared with
<jdbc:embedded-database>. - jpaVendorAdapter: Specifies the JPA vendor adapter. Here, a bean of the
HibernateJpaVendorAdapterclass can be used. This bean also provides thegenerateDdlproperty so that the database can be generated automatically.
- dataSource: Specifies the bean prepared with
Several beans are combined, but in the end, they are all for making the entity manager available. Also, although the entityManagerFactory setup here uses Hibernate, other libraries can be used. In that case, you need to configure it according to the vendor adapter you use.
Create the Entity Class
Now the preparation for using Spring Data JPA is finally complete. From here, let’s start coding to actually use Spring Data JPA.
Spring Data JPA uses classes called entities to handle tables created in a database. An entity reconstructs the table structure as a Java class. At the same time, data retrieved from the table is handled as instances of that entity.
As a simple sample entity class, create a class named SampleEntity in the com.devkuma.spring.db package as follows.
package com.devkuma.spring.db;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class SampleEntity {
@Id
@Column
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
@Column(length=50, nullable=false)
private String name;
@Column(length=100, nullable=true)
private String mail;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail;
}
public long getId() {
return id;
}
public SampleEntity() {
super();
}
public SampleEntity(String name, String mail) {
this();
this.name = name;
this.mail = mail;
}
public String toString() {
return "SampleEntity [id=" + id + ", name=" + name + ", mail=" + mail + "]";
}
}
In an entity class, the items included in the table are provided directly as fields. In other words, it is defined with the idea that a table is a class and columns are fields. The important point is that the fields are not merely defined; annotations are also added to each of them. These are summarized below.
@Entity
Add this to the entity class. This annotation indicates that the class is an entity class.@Column
Add this to fields. It indicates a table column. A field with this annotation is considered to store the value of a column with the same name. Therefore, its value must have the same type as the column. The sample also has the following.This writes column properties inside the parentheses. In this way, properties to set on the column can also be written together in the annotation.@Column(length=50, nullable=false)@Id
This annotation is attached only to the firstidfield. It indicates the primary key, and the field with this annotation is the primary key column of the table.@GeneratedValue(strategy=GenerationType.AUTO)
This is also attached to theidfield. It relates to automatic value generation. Specifyingstrategy=GenerationType.AUTOautomatically sets the value.
All added fields are private and can be accessed through setter and getter methods. There are also two kinds of constructors and a toString method, but these are not required for an entity. Prepare them as needed.
Use the Database
Now let’s actually use the database. Create an App class in the com.devkuma.spring.db package and write the following source code.
package com.devkuma.spring.db;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("dbbean.xml");
EntityManagerFactory factory = app.getBean(EntityManagerFactory.class);
EntityManager manager = factory.createEntityManager();
makeDummyData(manager);
// get list
Query query = manager.createQuery("from SampleEntity");
List list = query.getResultList();
printList(list);
System.out.println("...ok.");
}
// create dummy entity data.
public static void makeDummyData(EntityManager manager) {
EntityTransaction transaction = manager.getTransaction();
transaction.begin();
manager.persist(new SampleEntity("tuyano", "syoda@tuyano.com"));
manager.persist(new SampleEntity("hanako", "hanako@flower"));
manager.persist(new SampleEntity("taro", "taro@yamada"));
manager.persist(new SampleEntity("sachiko", "sachico@happy"));
manager.flush();
transaction.commit();
}
// print all entity.
public static void printList(List list) {
for (Object item : list) {
System.out.println(item);
}
}
}
After it is complete, run the App class. You should see text output like the following.
SampleEntity [id = 1 name = tuyano, mail=syoda@tuyano.com]
SampleEntity [id = 2 name = hanako, mail = hanako @ flower]
SampleEntity [id = 3 name = taro, mail = taro @ yamada]
SampleEntity [id = 4 name = sachiko, mail = sachico @ happy]
... ok.
This retrieves and displays the entities prepared as dummy data from the database. Here, a makeDummyData method for generating dummy data and a printList method for printing the contents of the retrieved list are prepared. Let’s summarize briefly.
- Create
ApplicationContextFirst, prepare theApplicationContext app = new ClassPathXmlApplicationContext( "dbbean.xml");ApplicationContextinstance we usually create. Here, thedbbean.xmlfile is specified. - Obtain an
EntityManagerFactoryinstanceObtain the entity manager factory bean prepared in the bean configuration file. Here, the class value ofEntityManagerFactory factory = app.getBean(EntityManagerFactory.class);EntityManagerFactoryis specified as the argument. - Create
EntityManagerGet anEntityManager manager = factory.createEntityManager();EntityManagerfrom the preparedEntityManagerFactory. This only requires calling thecreateEntityManagermethod.
Now the EntityManager is ready. Next, it can be used to save dummy data or retrieve all entities as a list.
For now, since this is the basic use of the database, it is enough to understand how to obtain the important EntityManager. Specific database access will be explained later.
Use a Bean Configuration Class
Instead of using a bean configuration file, you can define the configuration as a class. Previously, the entity manager factory was prepared in dbbean.xml; now let’s do the same thing with a class.
Here, create a class named SampleEntityConfig in the com.devkuma.spring.db package and prepare bean creation methods there. Rewrite the sample source code as follows.
package com.devkuma.spring.db;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
@Configuration
class SampleEntityConfig {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder =
new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.H2).build();
}
@Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter =
new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory =
new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.devkuma.spring.db");
factory.setDataSource(dataSource());
factory.afterPropertiesSet();
return factory.getObject();
}
}
Then modify the following code in the App class.
ApplicationContext app = new ClassPathXmlApplicationContext("dbbean.xml");
Change it as follows.
ApplicationContext app = new AnnotationConfigApplicationContext(SampleEntityConfig.class);
Now beans can be created by using the SampleEntityConfig class. dbbean.xml is no longer needed. Not only that, persistence.xml and application.properties are actually no longer needed either, because values are written directly in the class without application.properties. You can see that using a class prepares the entity manager more cleanly. Let’s summarize the key points.
Create DataSource
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.H2).build();
DataSource is created from an instance of the EmbeddedDatabaseBuilder class. Set the database type with setType, and call build to create it.
Create EntityManagerFactory
This requires a little more work. Roughly speaking, the work done here can be summarized as follows.
- Create a
HibernateJpaVendorAdapterinstance. - Create a
LocalContainerEntityManagerFactoryBeaninstance. - Set the
HibernateJpaVendorAdapteron theLocalContainerEntityManagerFactoryBeanwithsetJpaVendorAdapter. - Set other properties with methods such as
setPackagesToScanandsetDataSource. - Call
afterPropertiesSet. - Obtain the
EntityManagerinstance withgetObject.
There are several steps, which can feel cumbersome, but considering that beans can be created with Java code alone without any other files such as XML, this approach may be more convenient for Java programmers.