In this tutorial we will take a look into spring data jpa in detail. We will see integratation between spring data and spring boot with examples. We will perform different crud operations using spring data and check out different ways and advantages of using it. We will have some REST endpoints exposed through spring controller and we will be invoking these endpoints to perform different crud operations. We will also take a look into how to make use of entitymanager and hibernate session in spring data. If you are looking for spring boot hibernate example then visit here - spring boot hibernate example
Table of Contents 1. Why Spring Data 2. What is Spring Data JPA 3. Different Spring Data Repositories 4. Project Structure 5. Maven Dependencies 6. Spring Boot Config 6.1 Spring Application Class 7. JPA Datasource Configurations 7.1 Hikari Datasource Configurations 8.1 JPA Entity 8.2 Defining Spring Controller 8.3 Defining Service class 8.4 Defining DAO class 9. Database Scripts 10. Spring Boot 2 and JPA 11. Run Application
Why Spring Data
Spring data simplifies the data access operations to a very greater extent. The most compelling feature of spring data is the ability to create repository implementations automatically, at runtime, from a repository interface. Hence, you only define the dao interface and the operations you want to perform such as save, read, delete and spring data will provide the implementations at runtime. Not only this, it also provides many inbuilt features for paginations, querying, auditing etc. Spring data provides support for both relational and NoSql DB.
What is Spring Data JPA
Among the many modules provided by Spring Data such as Spring Data Solr, Spring Data MongoDB, Spring Data REST to deal with the persistence layer, Spring Data JPA is also a sub project to deal with persisitence layer. Spring data provides enhanced support for JPA based implementations. We only require to define our repository interfaces, including custom finder methods, and Spring will provide the implementation automatically at run-time.
Different Spring Data Repositories
Lets discuss about different interfaces provided by spring data JPA to deal with persistence layer.
Repository - It is the central interface in the spring data repository abstraction. This is defined as a marker interface.
CrudRepository - CrudRepository provides methods such as save(), findOne(), findAll(), delete() etc. for the CRUD operations. This interface extends the Repository interface. While creating our dao interface we extend this interface with our custom interface and just invoke the abstract methods defined in CrudRepository and spring data will take care of providing the corresponding implementations at run-time.
JpaRepository - It is a JPA specific extension of Repository. It extends CrudRepository and provides some extra JPA related method such as flushing the persistence context and delete record in a batch.
PagingAndSortingRepository - It also extends CrudRepository provide methods to do pagination and sorting records.
Project Structure
Let us first define the project structure.
Maven Dependencies
spring-boot-starter-parent
: It provides useful Maven defaults. It also provides a dependency-management section so that you can omit version tags for existing dependencies.
spring-boot-starter-web
: It includes all the dependencies required to create a web app. This will avoid lining up different spring common project versions.
spring-boot-starter-tomcat
: It enable an embedded Apache Tomcat 7 instance, by default.This can be also marked as provided if you wish to deploy the war to any other standalone tomcat.
spring-boot-starter-tomcat
: It provides key dependencies for Hibernate, Spring Data JPA and Spring ORM.
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.1.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <exclusions> <exclusion> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jdbc</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>mysql</groupId> &tartifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> </dependency> </dependencies>
Spring Boot Config
Spring Application class
@SpringBootApplication enables many defaults. It is a convenience annotation that adds @Configuration, @EnableAutoConfiguration, @EnableWebMvc, @ComponentScan
The main()
method uses Spring Boot SpringApplication.run() method to launch an application.
package com.devglan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Other Interesting Posts Spring Boot Hibernate 5 Example Spring Hibernate Integration Example Spring Boot Actuator Rest Endpoints Example Spring 5 Features and Enhancements Spring Boot Thymeleaf Example Securing REST API with Spring Boot Security Basic Authentication Spring Boot Security Password Encoding using Bcrypt Encoder Spring Security with Spring MVC Example Using Spring Boot Websocket spring Boot Integration Without STOMP with complete JavaConfig
JPA Datasource Configuration
Following is our sample datasource configuration. Spring boot automatically identifies the driver class name with the help of datasource url.
spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource.username=root spring.datasource.password=root
Hikari Datasource Configurations
In production, it is always recommended to use datasource that supports connection pooling because database connection creation is a slow process.Here in the example we will be using HikariDatasource instead. It provides many advanced features while configuring our datasource in comparison to other datasources such as connectionTimeout, idleTimeout, maxLifetime, connectionTestQuery, maximumPoolSize and very important one is leakDetectionThreshold.It is as advanced as detecting connection leaks by itself.It is also faster and lighter than other available datasource.Following is the configuration for HikariDatasource.Make sure you comment the datasource confguration in properties file.
HikariDatasource Config@Bean public DataSource dataSource() { HikariDataSource ds = new HikariDataSource(); ds.setMaximumPoolSize(100); ds.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource"); ds.addDataSourceProperty("url", "jdbc:mysql://localhost:3306/test"); ds.addDataSourceProperty("user", "root"); ds.addDataSourceProperty("password", "password"); ds.addDataSourceProperty("cachePrepStmts", true); ds.addDataSourceProperty("prepStmtCacheSize", 250); ds.addDataSourceProperty("prepStmtCacheSqlLimit", 2048); ds.addDataSourceProperty("useServerPrepStmts", true); return ds; }
We can also create Hikaridatasource using DataSourceBuilder as follow.While doing so the datasource related properties can be still there in proerties file.I like this way.
@Bean @ConfigurationProperties("spring.datasource") public HikariDataSource dataSource() { return DataSourceBuilder.create().type(HikariDataSource.class).build(); }
In order to use HikariDataSource, you must include following maven dependency. Checkout the latest version here - Hikari Maven
<dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>2.7.3</version> </dependency>
In this case, we need to explicitly tell spring boot to use our custom datasource while creating EntityManagerfactory.Following is a sample example.
@Bean(name = "entityManagerFactory") public EntityManagerFactory entityManagerFactory() { LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean(); emf.setDataSource(dataSource); emf.setJpaVendorAdapter(jpaVendorAdapter); emf.setPackagesToScan("com.mysource.model"); emf.setPersistenceUnitName("default"); emf.afterPropertiesSet(); return emf.getObject(); }
Server Side implementation
Entity Class
Following is the entity class.
UserDetails.javapackage com.devglan.model; @Entity @Table public class UserDetails { @Id @Column @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @Column private String firstName; @Column private String lastName; @Column private String email; @Column private String password; //getters and setters goes here
Defining Spring Controller
Following is the controller class. It exposes rest endpoints for our crud operations.
@Controller @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @RequestMapping(value = "/list", method = RequestMethod.GET) public ResponseEntity> userDetails() { List
userDetails = userService.getUserDetails(); return new ResponseEntity >(userDetails, HttpStatus.OK); } @RequestMapping(value = "/{id}", method = RequestMethod.GET) public ResponseEntity
findById(@PathVariable(name = "id", value = "id") Long id) { UserDetails userDetail = userService.findById(id); return new ResponseEntity (userDetail, HttpStatus.OK); } @RequestMapping(method = RequestMethod.POST) public ResponseEntity findById(@RequestBody UserDetails userDetails) { UserDetails userDetail = userService.save(userDetails); return new ResponseEntity (userDetail, HttpStatus.OK); } @RequestMapping(value = "/email/{email:.+}", method = RequestMethod.GET) public ResponseEntity findById(@PathVariable(name = "email", value = "email") String email) { UserDetails userDetail = userService.findByEmail(email); return new ResponseEntity (userDetail, HttpStatus.OK); } @RequestMapping(value = "/{id}", method = RequestMethod.DELETE) public ResponseEntity delete(@PathVariable(name = "id", value = "id") Long id) { userService.delete(id); return new ResponseEntity ("success", HttpStatus.OK); } }
Defining Service class
Following is the service class that acts as a bridge between controller and dao.
@Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public ListgetUserDetails() { return (List ) userDao.findAll(); } @Override public UserDetails findById(Long id) { return userDao.findOne(id); } @Override public UserDetails save(UserDetails user) { return userDao.save(user); } @Override public UserDetails findByEmail(String email) { return userDao.findByEmail(email); } @Override public void delete(Long id) { userDao.delete(id); } }
Defining DAO class
The UserDao interface extends CrudRepository
which has different crud methods such as create, findOne, delete etc and hence our UserDao automatically inherits them which is available for our service class to use. Its spring data which will generate the implementations at run time for these crud methods. Hence, we dont have to provide the implementations.
Notice the generic parameters in CrudRepository. Based on these parameters, Spring data will perform different crud operations at run time on our behalf.
Apart from the different default methods defined in the CrudRepository, we have defined our own method - findByEmail()
. We have one parameter defined in our entiry class as email and by the naming conventions as findByEmail, Spring data will automatically identify that this is a search operation by email of the user.
public interface UserDao extends CrudRepository{ UserDetails findByEmail(String email); }
Spring data is not limited to use of only JPA and some standards methods. Even it is possible to define some custom methods and custom operations too. You can also make use of JPA provided entitymanager to perform custom data manipulation as well as use hibernate session to make advanatage of different functions provided by hibernate.
Using EntityManager in Spring Data
Following is the implementation that uses entitymanager to save data in db while using spring data.
@Repository public class UserDaoImpl implements Userdao { @PersistenceContext private EntityManager entityManager; @Override public void save(UserDetails user) { entityManager.persist(user); } }
Using Hibernate Session in Spring Data
As we discussed, Spring data is not only limited to use of JPA, you can also make use of hibernate session and make use of different functions provided by hibernate.
@Repository public class UserDaoImpl implements UserDao { @PersistenceContext private EntityManager entityManager; public List getUserDetails() { Criteria criteria = entityManager.unwrap(Session.class).createCriteria(UserDetails.class); return criteria.list(); } }
Spring Boot 2 and JPA
Above configurations works well with spring boot version lessa then 2 but with the release of spring boot 2.0 we do not require any explicit configuration for Hikari datasource. Spring Boot 2 JPA has by default support for Hikari connection pooling. Hence, in the above configuration, remove the artifact of commons-dbcp and hikari artifact and with the rest of the configuration remaining same we can have Hikari connection pooling.
There are conventional methods removed for pagination and sorting.For example new PageRequest()
is deprecated.Following is an example to use Pageable in spring data JPA.The following method can either return the list or org.springframework.data.domain.Page
@Repository public interface UserPageableDao extends PagingAndSortingRepository{ //List listUsers(Pageable pageable); Page listUsers(Pageable pageable); }
From service implementation we can invoke this DAO method as below:
public ListgetUserDetails1() { Pageable pageable = PageRequest.of(0, 3, Sort.Direction.DESC,"createdOn"); Page page = userPageableDao.listUsers(pageable); return page.getContent(); } //findOne() is removed. @Override public UserDetails findById(Long id) { return userDao.findById(id).get(); } //delete(id) is removed @Override public void delete(Long id) { userDao.deleteById(id); }
Database Scripts
Following are some sample DML. We will be creating some dummy user details using following insert statements.
create table User_Details (id integer not null auto_increment, email varchar(255), first_Name varchar(255), last_Name varchar(255), password varchar(255), primary key (id)) ENGINE=InnoDB; INSERT INTO user_details(email,first_Name,last_Name,password) VALUES ('admin@admin.com','admin','admin','admin'); INSERT INTO user_details(email,first_Name,last_Name,password) VALUES ('john@gmail.com','john','doe','johndoe'); INSERT INTO user_details(email,first_Name,last_Name,password) VALUES ('sham@yahoo.com','sham','tis','shamtis');
Run Application
1. Run Application.java as a java application.
+2. Now hit the url - localhost:8080/user/list and you can see following.
3. You can also try for post request using postman or ARC as follow:
Similarly you can make other requests.
Conclusion
I hope this article served you that you were looking for. If you have anything that you want to add or share then please share it below in the comment section.