0% found this document useful (0 votes)
23 views34 pages

UNIT III Material

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
23 views34 pages

UNIT III Material

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 34

UNIT III

Spring Data JPA with Boot

Limitations of JDBC API


Drawbacks of JDBC API

InfyTel Application's data access layer has been implemented using JDBC API. But there are some
limitations of using JDBC API.

As seen in the demo when JDBC API is used for database operation, the developer needs to provide a lot of
data access code before and after the execution of a query. This increases the code size and it becomes
difficult to maintain and make changes.

All the exceptions thrown in JDBC have checked exceptions that require try-catch blocks in the code. This
also makes the code difficult to read and maintain.

If the database connection is not closed in an application, it will lead to resource leakage.

Let us understand the limitations of JDBC API

 A developer needs to open and close the connection.


 A developer has to create, prepare, and execute the statement and also maintain the resultset.
 A developer needs to specify the SQL statement(s), prepare, and execute the statement.
 A developer has to set up a loop for iterating through the result (if any).
 A developer has to take care of exceptions and handle transactions.

The above limitations can be solved with the technologies Spring ORM.

So Let's discuss more on ORM and also let's see some classes and interfaces of Spring ORM which will
help to overcome the above limitations. Later we'll look at some features of Spring ORM which
unnecessarily increase our repository implementations and will see how Spring Data JPA will help us
to completely remove the repository class implementations by using Spring ORM specifications internally.

ORM and Spring ORM


Need for ORM

To understand Spring Data JPA we need to know about ORM and Spring ORM

As seen in the previous demo of the InfyTel application where the persistence layer has been implemented
using JDBC API, there are several limitations and challenges. Let us now look at them.

JDBC, I/O, Serialization do not solve the problem of data persistence effectively. For a medium to be
effective, it needs to take care of the fundamental difference in the way Object-Oriented Programs(OOP)
and RDBMS deals with the data.

 In Programming languages like Java, the related information or the data will be persisted in the form
of hierarchical and interrelated objects.
 In the relational database, the data is persisted as table format or relations.
The greatest challenge in integrating the concepts of RDBMS and OOP is a mapping of the Java objects to
databases. When object and relational paradigms work with each other, a lot of technical and conceptual
difficulties arise, as mapping of an object to a table may not be possible in all the contexts. Storing and
retrieving Java objects using a Relational database exposes a paradigm mismatch called "Object-Relational
Impedance Mismatch". These differences are because of perception, style, and patterns involved in both the
paradigms that lead to the following paradigm mismatches:

 Granularity: Mismatch between the number of classes in the object model and the number of tables
in the relational model.
 Inheritance or Subtype: Inheritance is an object-oriented paradigm that is not available in RDBMS.
 Associations: In object-oriented programming, the association is represented using reference
variables, whereas, in the relational model foreign keys are used for associating two tables.
 Identity: In Java, object equality is determined by the "==" operator or "equals()" method,
whereas in RDBMS, uses the primary key to uniquely identify the records.
 Data Navigation: In Java, the dot(.) operator is used to travel through the object network, whereas,
in RDBMS join operation is used to move between related records.

Let's understand what is ORM on the next page.

What is ORM?

Object Relational Mapping (ORM) is a technique or design pattern, which maps object models with the
relational model. It has the following features:

 It resolves the object-relational impedance mismatch by mapping


o Java classes to tables in the database
o Instance variables to columns
o Objects to rows in the table
 It helps the developer to get rid of SQL queries. They can concentrate on the business logic and
work with the object model which leads to faster development of the application.
 It is database independent. All database vendors provide support for ORM. Hence, the application
becomes portable without worrying about the underlying database.

Benefits of Object Relational Mapping(ORM)

 ORM provides a programmatic approach to implement database operations.


 ORM maps Java objects to the relational database tables in an easier way based on simple
configuration.
 Supports simple query approaches like HQL(Hibernate Query language) and JPQL (Java
Persistence Query Language)
 Supports object-oriented concepts such as inheritance, mapping, etc.

To use ORM in Java applications Java Persistence API (JPA) specification is used. There are several
implementations of JPA available in the market, such as Hibernate, OpenJPA, DataNucleus, EclipseLink,
etc. EclipseLink is the reference implementation for JPA.

Note: Hibernate is one of the most popular implementations and in this course, our Spring Data JPA
applications internally use this implementation.

ORM Providers
The Java Persistence API (JPA) is a Java EE specification that defines how data persistence‐related tasks
are handled using object‐relational mapping (ORM) frameworks in Java applications. It provides the
following features:

 Defines an API for mapping the object model with the relational model
 Defines an API for performing CRUD operations
 Standardizes ORM features and functionalities in Java.
 Provides an object query language called Java Persistence Query Language (JPQL) for querying the
database.
 Provides Criteria API to fetch data over an object graph.

There are multiple providers available in the market which provides an implementation of JPA specification
such as EclipseLink, OpenJPA, Hibernate, etc. as shown below:

Hibernate is the most widely used framework among these.

Once you have understood about ORM and its providers let's look at Spring ORM in brief.

Spring ORM:

Spring Framework is the most popular open-source Java application framework which supports building all
types of Java applications like web applications, database-driven applications, batch applications, and many
more. Spring framework's features such as Dependency Injection and Aspect-Oriented Programming help in
developing a simple, easily testable, reusable, and maintainable application.

Spring is organized in a modular fashion. Developers can pick and choose the modules as per their needs.
Spring ORM is a module under the Spring umbrella that covers many persistence technologies, namely JPA,
JDO, Hibernate, and iBatis, etc. For each technology, the configuration basically consists of injecting a
DataSource bean into SessionFactory or EntityManagerFactory and helps in performing CRUD operations.

Spring ORM Repository implementation

Repository implementation using Spring ORM:

Spring ORM provides integration classes to integrate the application with ORM solutions such as JPA,
Hibernate, MyBatis to perform database operations and transaction management
smoothly. Hibernate specific exceptions need not be declared or caught as @Repository annotation. Spring
enables the exception of clean translation.

The repository implementation class requires appropriate persistence resource bean from Spring Framework
as below:

 JPA based repository uses EntityManagerFactory bean


 Hibernate based repository uses SessionFactory bean
JPA based repositories are the most convenient way of developing our repository layer of Spring ORM
applications as JPA is a specification and Hibernate is an implementation. So with little modification in the
future, we can migrate from one ORM implementation to another.

Developing the persistence layer using Spring ORM JPA possess the following advantages:

 Provides a programmatic approach to implement database operations.


 Maps Java objects to the relational database tables with help of entity classes based on simple
configuration.
 Supports HQL(Hibernate Query language) and JPQL (Java Persistence Query Language)
 Supports object-oriented concepts such as inheritance, mapping, etc.

So let's see additional configurations required for developing the repository layer of a Spring ORM JPA
application with Spring Boot.

Spring ORM JPA Configurations

Let's take the same InfyTel Customer management scenario and develop the repository layer to perform the
CRUD operations. In the Spring Boot application, a DAO(Data Access Object)/ repository class can be
defined using @Repository annotation.

@Repositoy:

It indicates the repository class(POJO class) in the persistence layer. Repository class is defined
using @Repository annotation at the class level. This annotation is a specialization
of @Component annotation for the persistence layer.

Benefits of the @Repository:

 Enables the Spring Framework auto scanning support to create a repository bean without the explicit
bean definition in the configuration file.
 Causes Spring exception translation(translates checked exceptions into unchecked exceptions).

EntityManagerFactory:

EntityManagerFactory will be used by the Spring Boot application to obtain an EntityManager instance.
An EntityManagerFactory is constructed for a specific database, and managing resources
efficiently provides an efficient way to construct multiple EntityManagers instances for that database to
perform CRUD operations. Spring Boot generally uses LocalContainerEntityManagerFactoryBean for full
JPA capabilities.

The main dependency of LocalContainerEntityManagerFactoryBean is:

 Datasource

Datasource:

Spring obtains the connection to the database through DataSource bean which is the mandatory
configuration. It allows Spring container to hide database-specific details from the application code.
Spring's DriverManagerDataSource class is used to define the Datasource bean. Spring Boot will
automatically create the Datasource bean by reading the database details like driver details, connection URL,
username, and password present in the application.properties file.

Sample application.properties:

1. spring.datasource.driverClassName=com.mysql.jdbc.Driver
2. spring.datasource.url=jdbc:mysql://localhost:3306/ormjpa
3. spring.datasource.username=root

4. spring.datasource.password=root

EntityManager

Once the EntityManagerFactory is properly configured, it provides an instance of EntityManager interface


whose methods can be used to interact with the database for CRUD operations with the help of entity objects.
Some important methods of this interface are as follows:

 void persist(Object entity)


 find(Class entityClass, Object primaryKey)
 void remove(Object entity)
 void detach(Object entity)
 createQuery(JPQL)

ORM application generally uses Entity classes to support programmatic database operations so let's see what
is an Entity class and its features.

Entity Class

JPA needs an Entity class to perform all the CRUD operations because Entities can represent fine-grained
persistent objects and they are not remotely accessible components. An entity can aggregate objects together
and effectively persist data and related objects using the transactional, security, and concurrency services of
a JPA persistence provider. Let's discuss more on Entity classes.

EntityClass:
An Entity class is a class in Java that is mapped to a database table in a relational database. Entity classes
can be created using @Entity annotation from javax.persistence package.

Let's map our Customer class used in the InfyTel application to a database table Customer and each of the
attributes of the class phoneNumber, name, age, gender, address, and planId maps to the columns of the
Customer table. The Customer class is persisted in the database it is also known as an Entity class.
Each Java object which is created corresponds to a row in the given database table.
Eg: Customer customer= new Customer(9009009009L, "Jack", 27, 'M', "BBSR", 1);

Let's create a sample entity class for our InfyTel application i.e. "Customer.java" :

1. package com.infytel.entity;
2. import javax.persistence.Column;
3. import javax.persistence.Entity;
4. import javax.persistence.Id;
5. @Entity
6. public class Customer {
7.
8. @Id
9. @Column(name = "phone_no")
10. private Long phoneNumber;
11. private String name;
12. private Integer age;
13. private Character gender;
14. private String address;
15. @Column(name = "plan_id")
16. private Integer planId;
17. //constructors
18. //getters and setters

19. }

Few of the common annotations used for defining an Entity Class are explained below:

ANNOTATION DEFINITION
@Entity Declares an Entity class
Declares one of the attributes of the entity class as the primary key in the
@Id
table in the database
@Column Declares mapping of the particular column in the database to an attribute
@Table Declares mapping of a certain entity class to a table name in a database
Specified for persistent table fields or attributes of the type java.util.Date
and java.util.Calendar. It solves one of the major issues of converting the
@Temporal
date and time values from java object to compatible database type and
retrieving back to the application
@Transient It will not be persisted into the database

Note:

 All the annotations explained in the above table are available in javax.persistence package.
 In Hibernate 5.0 you don’t need any @Temporal annotations or converter to persist the classes of
the Date and Time API. You can use them in the same way as any other supported attribute types.

So as we can see a lot of coding effort has to be done in the repository class implementation to perform our
CRUD operations. So let's see a complete demo using Spring ORM JPA to perform CRUD
operation, understand it's drawbacks and why we need Spring Data JPA.

Why Spring Data JPA?


We saw how to develop the data access layer of an application using the Spring ORM JPA (with Spring
Boot) module of the Spring framework.

Let us look at the limitations while using these approaches:

 The Programmer has to write the code to perform common database operations(CRUD operations)
in repository class implementation.
 A developer can define the required database access methods in the repository implementation class
in his/her own way, which leads to inconsistency in the data access layer implementation.

So in this course, we will see how Spring Data JPA helps us to overcome these limitations.

Now let's look at the high-level design of our InfyTel application when it will use the Spring Data JPA
module of Spring Framework.

Higlevel Diagram of InfyTel Customer using Spring Data JPA

InfyTel system's data access layer implementation using Spring Data JPA is as shown below:

Now let's understand What's Spring Data JPA.

What is Spring Data JPA?


Spring Data is a high-level project from Spring whose objective is to unify and ease access to different types
of data access technologies including both SQL and NoSQL data stores. It has many sub-projects.

Spring Data simplifies the data access layer by removing the repository(DAO) implementations entirely
from your application. Now, the only artifact that needs to be explicitly defined is the interface. Let us look
at this with an example later in this course.

Spring Data supports many environments as shown below:

 Core Project supports concepts applicable to all Spring Data projects.


 Sub Projects support technology-specific details.
Spring Data JPA is one of the Spring Data subproject to support the implementation of JPA-based

repositories.
Spring Data JPA – Interfaces

Spring Data JPA helps to implement the persistence layer by reducing the effort that is actually needed.

As a part of the core project, Spring Data Commons provides basic interfaces to support the following
commonly used database operations:

 Performing CRUD (create, read, update, delete) operations


 Sorting of data
 Pagination of data
 Spring Data provides persistent technology-specific abstractions as interfaces through its sub-
projects.
 JpaRepository interface to support JPA.
 MongoRepository interface to support MongoDB and many more.
Let us understand more about how to implement the application data access layer using Spring Data JPA.
Spring Data JPA - Required dependencies

Spring Data abstracts the data access technology-specific details from your application. Now, the
application has to extend only the relevant interface of Spring Data to perform required database
operations.

For example, if you would like to implement your application's data access layer using JPA repository, then
your application has to define an interface that extends the JpaRepository interface.

Let us understand how Spring Data JPA applications can be created with Spring Boot

Spring Data JPA with Spring Boot


Introduction to Spring Boot

Let us understand Spring Boot


We have learned that Spring is a lightweight framework for developing enterprise applications. But using
Spring for application development is challenging for developer because of the following reason which
reduces productivity and increases the development time:

1. Configuration

Developing a Spring application requires a lot of configuration. This configuration also needs to be
overridden for different environments like production, development, testing, etc. For example, the database
used by the testing team may be different from the one used by the development team. So we have to spend
a lot of time writing configuration instead of writing application logic for solving business problems.

2. Project Dependency Management

When you develop a Spring application you have to search for all compatible dependencies for the Spring
version that you are using and then manually configure them. If the wrong version of dependencies is
selected, then it will be an uphill task to solve this problem. Also for every new feature added to the
application, the appropriate dependency needs to be identified and added. All this reduces productivity.

So to handle all these kinds of challenges Spring Boot came in the market.

What is Spring Boot?

Spring Boot is a framework built on the top Spring framework that helps developers build Spring-based
applications quickly and easily. The main goal of Spring Boot is to quickly create Spring-based applications
without requiring developers to write the same boilerplate configuration again and again.

But how does it work? It works because of the following reasons,

1. Spring Boot is an opinionated framework

Spring Boot forms opinions. It means that Spring Boot has some sensible defaults which you can use to
quickly build your application. For example, Spring Boot uses embedded Tomcat as the default web
container.

2. Spring Boot is customizable

Though Spring Boot has its defaults, you can easily customize it at any time during your development based
on your needs. For example, if you prefer log4j for logging over Spring Boot built-in logging support then
you can easily make dependency change in your pom.xml file to replace the default logger with log4j
dependencies.

The main Spring Boot features are as follows:

1. Starter Dependencies
2. Automatic Configuration
3. Spring Boot Actuator
4. Easy-to-use Embedded Servlet Container Support

Creating a Spring Boot Application

There are multiple approaches to create a Spring Boot application. You can use any of the following
approaches to create the application:

 Using Spring Initializr


 Using the Spring Tool Suite (STS)
 Using Spring Boot CLI

In this course, you will learn how to use Spring Initializr for creating Spring Data JPA applications.

Spring Data JPA Configuration


rDefining Repository Interfaceing Data JPA Configuration
We have seen how to create a Spring Boot project with the necessary dependencies for Spring Data JPA.

Let's now look at how to implement the required interfaces for the persistence layer of the InfyTel Customer
management application.

We need to define a repository interface for InfyTel Customer as below when we need to insert/delete a
Customer data:

In the data access layer of the application, we need only the interface extending Spring’s JpaRepository<T,
K> interface as shown below:

1. public interface CustomerRepository extends


JpaRepository<Customer, Long> {

2. }

Here, the CustomerRepository interface extends a Spring provided interface JpaRepository but the below
details needs to be provided to Spring through JpaRepository<Customer, Long> interface:

1. Entity class name to which you need the database operations (In this example, entity class is
Customer).
2. The Datatype of the primary key of your entity class (Customer class primary key type is a long).

Spring scans the interface that extends the JpaRepository interface, auto-generates common CRUD methods,
paging, and sorting methods at run time through a proxy object.

@Repository annotation can be used at the user-defined interface as Spring provides repository
implementation of this interface. However, it is optional to mention the annotation explicitly because Spring
auto-detects this interface as a Repository.

1. @Repository
2. public interface CustomerRepository extends
JpaRepository<Customer, Long> {
3.

4. }

Note: It is recommended to give interface name as entity class name concatenated with Repository. Hence
in the example, it is defined as an interface CustomerRepository for the entity class Customer.

Spring Data JPA Repository hierarchy


The below diagram shows the methods available to the application from Spring:

If the application interface is extending the JpaRepository interface, then Spring provides auto
implementation of all the above-listed methods and makes them available for the application. An appropriate
method can be used in the application depending on the required database operation.

In the demo discussed saveAndFlush() and delete() methods of Spring are used to perform insertion and
removal operations using repository bean.

Additional configurations – DataSource

As all of us know Spring obtains the connection to the database through DataSource bean which is the
mandatory configuration. It allows Spring container to hide database-specific details from the application
code. But as we are developing our Spring Data JPA application using Spring Boot so there is no need to
explicitly definine the DataSource bean in a configuration file.

Spring's DriverManagerDataSource class is used to define the Datasource bean. Spring Boot will
automatically create the Datasource bean by reading the database details like driver details, connection URL,
username, and password present in the application.properties file.
So we need to define the below configurations in the application.properties.

1. spring.datasource.driverClassName=com.mysql.jdbc.Driver
2. spring.datasource.url=jdbc:mysql://localhost:3306/sample
3. spring.datasource.username=root

4. spring.datasource.password=root

Let's see how our service layer and repository layer should be implemented for implementing CRUD
operations using Spring Data JPA with Spring Boot.

CRUD Operation with Spring Data JPA - Repository Layer

As seen in the Spring Data JPA Repository hierarchy when we are extending
the JpaRepository interface then Spring provides the auto implementation of all the methods
from JpaRepository, PagingAndSortingRepository, CrudRepository and will make them available to the
application. An appropriate method can be used in the service layer of the application depending on the
required database operation.

So our CustomerRepository interface will look as below:

1. package com.infyTel.repository;
2. import org.springframework.data.jpa.repository.JpaRepository;
3. import com.infyTel.domain.Customer;
4. public interface CustomerRepository extends
JpaRepository<Customer, Long>{

5. }

Spring Data JPA provides a default implementation for each method defined by one of its repository
interfaces. That means that you no longer need to implement basic read or write operations by implementing
the above interface. So for implementing our CRUD operations we are going to use 4 methods from their
respective interfaces, which are listed below:

 saveAndFlush(S entity) of JpaRepository which saves an entity and flushes changes instantly.
 deleteById(ID id) of CrudRepository which deletes the entity based on the given id/primary key.
 findById(ID id) of CrudRepository which returns a given entity based on the given id/primary key.
 save(S entity) of CrudRepository which saves the given entity in the database.

Now let's look at how the service layer is implemented and the service implementation class uses these 4
methods depending on the required database operation.

CRUD Operation with Spring Data JPA - Service Layer

The service interface will act as a bridge between our Client class and Service implementation class. So to
perform CRUD operation we can define all the required methods in the CustomerService interface as below:

CustomerService.java:
1. package com.infyTel.service;
2. import com.infyTel.dto.CustomerDTO;
3. public interface CustomerService {
4. public void insertCustomer(CustomerDTO Customer) ;
5. public void removeCustomer(Long phoneNo);
6. public CustomerDTO getCustomer(Long phoneNo);
7. public String updateCustomer(Long phoneNo,Integer newPlanId);

8. }

The service implementation class invokes repository methods through repository bean to perform the
required CRUD operation as shown below:

CustomerServiceImpl.java:

1. package com.infyTel.service;
2. import java.util.Optional;
3. import org.springframework.beans.factory.annotation.Autowired;
4. import org.springframework.stereotype.Service;
5. import com.infyTel.domain.Customer;
6. import com.infyTel.dto.CustomerDTO;
7. import com.infyTel.repository.CustomerRepository;
8. @Service("customerService")
9. public class CustomerServiceImpl implements CustomerService {
10. @Autowired
11. private CustomerRepository repository;
12. @Override
13. public void insertCustomer(CustomerDTO customer) {
14.
repository.saveAndFlush(CustomerDTO.prepareCustomerEntity(custom
er));
15. }
16. @Override
17. public void removeCustomer(Long phoneNo) {
18. repository.deleteById(phoneNo);
19. }
20. @Override
21. public CustomerDTO getCustomer(Long phoneNo) {
22. Optional<Customer> optionalCustomer =
repository.findById(phoneNo);
23. Customer customerEntity =
optionalCustomer.get();// Converting Optional<Customer> to
Customer
24. CustomerDTO customerDTO =
Customer.prepareCustomerDTO(customerEntity);
25. return customerDTO;
26. }
27. @Override
28. public String updateCustomer(Long phoneNo, Integer
newPlanId) {
29. Optional<Customer> optionalCustomer =
repository.findById(phoneNo);
30. Customer customerEntity = optionalCustomer.get();
31. customerEntity.setPlanId(newPlanId);
32. repository.save(customerEntity);
33. return "The plan for the customer with phone
number :" + phoneNo + " has been updated successfully.";
34. }

35. }

In service class implementation, we are autowiring CustomerRepository instance to make use of required
repository methods in the service layer.

Even though we are defining CustomerRepository as an interface, we are able to get an instance of
CustomerRepository because Spring internally provides a proxy object for this interface with auto-generated
methods. Hence we could autowire bean of CustomerRepository.

Let us see the complete demo to implement CRUD operation for a better understanding.

Pagination and Sorting


Spring Data JPA – Pagination

Let us now understand paging and sorting support from Spring Data.

PagingAndSortingRepository interface of Spring Data Commons provides methods to support paging and
sorting functionalities.

1. public interface PagingAndSortingRepository<T, ID extends


Serializable> extends CrudRepository<T, ID> {
2. Iterable<T> findAll(Sort sort);
3. Page<T> findAll(Pageable pageable);

4. }

A Page object provides the data for the requested page as well as additional information like total result
count, page index, and so on.

Pageable instance dynamically adds paging details to statically defined query. Let us see more details in the
example.

Pagination

The steps to paginate the query results are:

Step 1: JpaRepository is a sub-interface of the PagingAndSortingRepository interface. The Application


standard interface has to extend JpaRepository to get paging and sorting methods along
with common CRUD methods.

1. public interface CustomerRepository extends JpaRepository<Customer,


Long> {
2.
3. }

Note: findAll(Pageable page) and findAll(Sort sort) methods are internally provided by Spring.

Step 2: In client code, create a org.springframework.data.domain.Pageable object by


instantiating org.springframework.data.domain.PageRequest describing the details of the requested page is
shown below:

To ask for the required page by specifying page size, a new PageRequest instance must be created.

1. //First argument '0" indicates first page and second argument 4


represents number of records.

2. Pageable pageable = PageRequest.of(0, 4);

Step 3: In the client code, pass the Pageable object to the repository method as a method parameter.

1. Page<Customer> customers = customerRepository.findAll(pageable);

Sorting is to order query results based on the property values of the entity class.

For example, to sort employee records based on the employee's first name field can be done using the below
steps:

Step 1: Standard interface has to extend JpaRepository to use sorting method provided by Spring

1. public interface CustomerRepository extends


JpaRepository<Customer, Long> {
2.

3. }

Step 2: In the client code, create org.springframework.data.domain.Sort instance describing the sorting
order based on the entity property either as ascending or descending and pass the instance of Sort to the
repository method.

1. customerRepository.findAll(Sort.by(Sort.Direction.ASC,"name"));

In the Sort() method used above,


 The first parameter specifies the order of sorting i.e. is ascending order.
 The second parameter specifies the field value for sorting.

Query Approaches
Spring Data JPA - Query Approaches

So far, you have learned how Spring provides common database operations.

Spring Data by default provides the following query methods through its interface:

 findAll //Returns all entities


 findById(ID id) //Returns the entity depending upon given id

What if one wants to query customer records based on the customer's address?

How does Spring support this scenario?

Spring supports these kinds of scenarios using the following approaches:

 Query creation based on the method name.


 Query creation using @NamedQuery: JPA named queries through a naming convention.
 Query creation using @Query: annotate the query method with @Query.

Let us understand the approaches in detail.

Query method names are derived by combining the property name of an entity with supported keywords
such as "findBy", "getBy", "readBy" or "queryBy".

1. //method name where in <Op> is optional, it can be


Gt,Lt,Ne,Between,Like etc..

2. findBy <DataMember><Op>

Example: Consider the Customer class as shown below:

1. public class Customer {


2.
3. private Long phoneNumber;
4. private String name;
5. private Integer age;
6. private Character gender;
7. private String address;
8. private Integer planId;
9. //getters and setters

10. }
To query a record based on the address using query creation by the method name, the following method has
to be added to the CustomerRepository interface.

1. interface CustomerRepository extends JpaRepository<Customer,


Long>{
2. Customer findByAddress(String address); // method
declared

3. }

The programmer has to provide only the method declaration in the interface. Spring takes care of auto-
generating the query, the mechanism strips the prefix findBy from the method and considers the remaining
part of the method name and arguments to construct a query.

Let us understand this concept in detail, through a demo.

Consider the Customer and Address classes given below:

Customer.java

1. @Entity
2. public class Customer{
3. @Id
4. int customerId;
5. boolean active;
6. int creditPoints;
7. String firstName;
8. String lastName;
9. String contactNumber;
10. String email;
11. @OneToOne( cascade = CascadeType.ALL)
12. @JoinColumn
13. Address address;
14. -----------

15. }

Address.java

1. @Entity
2. public class Address {
3. @Id
4. private int addressId;
5. private String city;
6. private String pincode;
7. ----------------

8. }
The CustomerRepository interface with some common findBy methods is shown below:

1. public interface CustomerRepository extends


JpaRepository<Customer, Integer> {
2.
3. // Query record based on email
4. // Equivalent JPQL: select c from Customer c where c.email=?
5. Customer findByEmail(String email);
6.
7. // Query records based on LastName is like the provided last
name
8. // select c from Customer c where c.lastName LIKE
CONCAT('%',?,'%')
9. List<Customer> findByLastNameLike(String lastname);
10.
11. // Query records based on email or contact number
12. // select c from Customer c where c.email=? or
c.contactNumber=?
13. List<Customer> findByEmailOrContactNumber(String email,
String number);
14.
15. // Query records based on FirstName and city details.
Following query creates the property traversal for city as
Customer.address.city
16. // select c from Customer c where c.firstName=? and
c.address.city=?
17. List<Customer> findByFirstNameAndAddress_City(String fname,
String city);
18.
19. // Query records based on last name and order by ascending
based on first name
20. // select c from Customer c where c.lastName=? order by
c.firstName
21. List<Customer> findByLastNameOrderByFirstNameAsc(String
lastname);
22.
23. // Query records based on specified list of cities
24. //select c from Customer c where c.address.city in ?1
25. List<Customer> findByAddress_CityIn(Collection<String>
cities);
26.
27. // Query records based if customer is active
28. //select c from Customer c where c.active = true
29. List<Customer> findByActiveTrue();
30.
31. // Query records based on creditPoints >= specified value
32. //select c from Customer c where c.creditPoints >=?1
33. List<Customer> findByCreditPointsGreaterThanEqual(int points)
;
34.
35. // Query records based on creditpoints between specified
values
36. //select c from Customer c where c.creditPoints between ?1
and ?2
37. List<Customer> findByCreditPointsBetween(int point1, int
point2)
38. }
39.

Note:

List<Customer> findByFirstNameAndAddress_City(String fname, String city)

It can also be written as:

List<Customer> findByFirstNameAndAddressCity(String fname, String city);

In case there is a property by name “addressCity” in Customer class then to resolve this ambiguity we can
add _ inside findBy method for manual traversal.

So far, we learned the following Query creation approaches in Spring Data JPA.

 Query creation based on the method name.


 Query creation using @NamedQuery: JPA named queries through a naming convention.
 Query creation using @Query: annotate your query method with @Query.

If a query is provided using more than one approach in an application. What is the default precedence given
by the Spring?

Following is the order of default precedence:

1. @Query always takes high precedence over other options


2. @NameQuery
3. findBy methods

Note: If a developer wants to change the query precedence, then he can provide with extra configuration.
This is not been discussed in this course.

NamedQueries and Query


Spring Data JPA - Query Creation Using JPA NamedQueries

By now you know, how to support a query through a method name.

Though a query created from the method name suits very well but, in certain situations, it is difficult to
derive a method name for the required query.

The following options can be used in these scenarios:

1. Using JPA NamedQueries: JPA named queries through a naming convention


2. Using @Query: Use @Query annotation to your query method

Let us now understand JPA NamedQueries:

Define annotation-based configuration for a NamedQuery at entity class with @NamedQuery annotation
specifying query name with the actual query.
1. @Entity
2. //name starts with the entity class name followed by the method
name separated by a dot.
3. @NamedQuery(name = "Customer.findByAddress", query = "select c
from Customer c where c.address = ?1")
4. public class Customer {
5.
6. @Id
7. @Column(name = "phone_no")
8. private Long phoneNumber;
9. private String name;
10. private Integer age;
11. private Character gender;
12. private String address;
13. --------

14. }

Now for executing this named query one needs to specify an interface as given below with method
declaration.

1. public interface CustomerRepository extends


JpaRepository<Customer, Long>{
2. Customer findByAddress(String address);
3.

4. }

Spring Data will map a call to findByAddress() method to a NamedQuery whose name starts with
entity class followed by a dot with the method name. Hence, in the above code, Spring will
use the NamedQuery with the name Customer.findByAddress() method instead of creating it.

NamedQuery approach has advantage as maintenance costs are less because the queries are provided through
the class. However, the drawback is that for every new query declaration domain class needs to be
recompiled.

Spring Data JPA - Query Creation Using @Query Annotation

The NamedQueries approach is valid for the small number of queries.

@Query annotation can be used to specify query details at repository interface methods instead of specifying
at entity class. This will also reduce the entity class from persistence related information.

Queries annotated to the query method has high priority than queries defined using @NamedQuery.

@Query is used to write flexible queries to fetch data.

Example: Declare query at the method level using @Query.


1. public interface CustomerRepository extends JpaRepository<Customer,
Long>{
2. //Query string is in JPQL
3. @Query("select cus from Customer cus where cus.address = ?1")
4. Customer findByAddress(String address);
5.

6. }

@Query annotation supports both JPQL (Java Persistence Query Language) and native SQL queries.

By default, it supports JPQL. The nativeQuery attribute must be set to true to support native SQL.

Example: Declare query at the method level using @Query with nativeQuery set to true.

1. public interface CustomerRepository extends


JpaRepository<Customer, Long>{
2. //Query string is in SQL
3. @Query("select cus from Customer cus where cus.address = ?1",
nativeQuery = true)
4. Customer findByAddress(String address);
5.

6. }

The disadvantage of writing queries in native SQL is that they become vendor-specific database and hence
portability becomes a challenge. Thus, both @NamedQuery and @Query supports JPQL.

Now, what is JPQL?

JPQL:

JPQL is an object-oriented query language that is used to perform database operations on persistent entities.
Instead of a database table, JPQL uses the entity object model to operate the SQL queries. Here, the role of
JPA is to transform JPQL into SQL. Thus, it provides an easy platform for developers to handle SQL tasks.

Features:

The features of JPQL are that it can:

 perform join operations


 update and delete data in a bulk
 perform an aggregate function with sorting and grouping clauses
 provide both single and multiple value result types

Creating Queries using JPQL:

JPQL provides two methods that can be used to perform database operations. They are: -
1. Query createQuery(String name) - The createQuery() method of EntityManager interface is used
to create an instance of the Hibernate Query interface for executing JPQL statement. This method
creates dynamic queries that can be defined within business logic.

Some of the examples of JPQL using createQuery method:(assuming the entity class name as -
'CustomerEntity' which is mapped to a relational table 'Customer')

 Fetching all the Customer names:

1. Query query = em.createQuery("Select c.name from CustomerEntity

c");

 Updating the plan of a customer:

1. Query query = em.createQuery( "update CustomerEntity SET planId=5


where phoneNumber=7022713766");

2. query.executeUpdate();

 Deleting a customer:

1. Query query = em.createQuery( "delete from CustomerEntity where


phoneNumber=7022713766");

2. query.executeUpdate();

2. Query createNamedQuery(String name) - The createNamedQuery() method of EntityManager


interface is used to create an instance of the Hibernate Query interface for executing named queries.
This method is used to create static queries that can be defined in the entity class.

Let's see a simple example of JPQL using createNamedQuery method to fetch all the details of customers in
InfyTel application:(Assume the entity class name is - 'CustomerEntity' which is mapped to a relational table
'Customer')

1. @NamedQuery(name = "getAll" , query = "Select c from

CustomerEntity s")

Let us understand @Query and @NamedQuery through a demo.

Why Spring Transaction?


InfyTel application transaction requirement is implemented using Spring Transaction Management.

For the InfyTel application, consider a scenario where the admin of the InfyTel wants to deactivate a Plan.
Once a Plan is deactivated, the Customer should be assigned with immediate next active Plan.

So, once a Plan is deactivated by the admin of the InfyTel, the Customer table should be updated with the
immediate next active plan as well as the plan name in the Customer table should be updated accordingly.

This task requires the application to perform an update on two database tables Customer and Plan. What
should happen if one of the table updates fails, should it continue with another table update?

The answer is NO. The application should not continue with other updates in order to maintain its data
integrity and consistency.

The application should not do any changes to both the tables in case of failure in any one of the
operations. Update of Customer details should be successful only if the update on both Plan and Customer
table is successful.

How do we achieve this kind of requirement in enterprise applications?

This can be achieved by executing related database operations in a transaction scope.

When we implement transaction using JDBC API, it has few limitations like:

 Transaction related code is mixed with application code, hence it is difficult to maintain the code.
 Requires a lot of code modification to migrate between local and global transactions in an
application.

Let us look at how the Spring transaction helps to overcome these limitations.

Spring Declarative Transaction


The Spring framework provides a common transaction API irrespective of underlying transaction
technologies such as JDBC, Hibernate, JPA, and JTA.

You can switch from one technology to another by modifying the application's Spring configuration. Hence
you need not modify your business logic anytime.
Spring provides an abstract layer for transaction management by hiding the complexity of underlying
transaction APIs from the application.

 Spring supports both local and global transactions using a consistent approach with minimal
modifications through configuration.
 Spring supports both declarative and programmatic transaction approaches.

Different ways to achieve Spring transaction:

Type Definition Implementation


Spring applies the required
transaction to the application code in  Using pure XML configuration
Declarative a declarative way using a simple  Using @Transactional
Transaction configuration. Spring internally uses annotation approach
Spring AOP to provide transaction
logic to the application code.
The Required transaction is
achieved by adding transaction-
 Using the TransactionTemplate
related code in the application code.
(adopts the same approach as
This approach is used for more fine
JdbcTemplate)
Programmatic level control of transaction
 Using a
Transaction requirements. This mixes the
PlatformTransactionManager
transaction functionality with
implementation.
the business logic and hence it is
recommended to use only based on
the need.

Which is the preferred approach to implement Spring transactions?

Declarative transaction management is the most commonly used approach by Spring Framework users.
This option keeps the application code separate from the transaction serves as the required transaction is
provided through the only configuration.

Let us proceed to understand, how Spring declarative transactions can be implemented using the annotation-
based approach in the Spring Data JPA application in detail.

Note:

 In this course, we will be covering only Spring declarative transactions using the annotation-based
approach.
 Spring Declarative Transaction is treated as an aspect. Spring will apply the required transaction at
run time using Spring AOP.

Considering the InfyTel scenario update the Customer's current plan and Plan details. The InfyTel
application uses Spring ORM for data access layer implementation. Let us now apply the Spring transaction
to this application.

This requirement provides an update on the following tables:

 Customer table: To update the current plan.


 Plan table: To update the plan details.

The important steps to implement Spring declarative transaction in Spring ORM application is :

 Add @Transactional annotation on methods that are required to be executed in the transaction scope
as all other things like dependencies management, etc are already taken care of by spring-boot-
starter-data-jpa jar
 Spring Data JPA Dependency:

1. <dependency>
2. <groupId>org.springframework.boot</groupId>
3. <artifactId>spring-boot-starter-data-
jpa</artifactId>

4. </dependency>

MySQL Driver dependency:

1. <dependency>
2. <groupId>mysql</groupId>
3. <artifactId>mysql-connector-java</artifactId>
4. <scope>runtime</scope>

5. </dependency>

We can implement Spring declarative transactions using the annotation-based approach.

Let us understand more on @Transactional annotation.


@Transactional annotation offers ease-of-use to define the transaction requirement at method, interface, or
class level.

Through declarative transaction management, update (Customer customer) method can be executed in
transaction scope using Spring.

1. public class CustomerServiceImpl {


2. ------------------------
3. @Transactional
4. public void update(Customer customer) {
5. //Method to update the current plan in Customer table
6. customerDAO.update(customer);
7. //Method to update the new plan details in Plan table
8. planDAO.updatePlan(customer.getPlan());
9. }
10.

11. }

This annotation will be identified automatically by Spring Boot if we have already included the spring-boot-
starter-data-jpa jar.

Should the developer use @Transactional annotation before every method?

No, @Transactional annotation can be placed at the class level which makes all its methods execute in a
transaction scope. For e.g. insertCustomer() and updateCustomerDetails() methods executes in transaction
scope.

1. @Transactional // This annotation makes all the methods of


this class to execute in transaction scope
2. public class CustomerServiceImpl {
3. -----------
4. public void insertCustomer(Customer customer) {
5. ------------------
6. }
7.
8. public void updateCustomerDetails(Customer customer) {
9. ------------------
10. }

11. }

The key interface to implement the Spring transaction is


org.springframework.transaction.PlatformTransactionManager Interface.

There are different implementations available for PlatformTransactionManager to support different data
access technologies such as JDBC, JTA, Hibernate, JPA and so on.

The PlatformTransactionManager implementations are responsible for managing transactions. Hence,


they are transaction managers.
The following table describes some of the commonly used transaction managers:

TransactionManager Data Access Technique


DataSourceTransactionManager JDBC
HibernateTransactionManager Hibernate
JpaTransactionManager JPA
JtaTransactionManager Distributed transaction

Transaction managers can be defined as any other beans in the Spring configuration only if we are not using
Spring Boot.

Since the InfyTel application is developed using Spring Boot and Spring Data JPA, So no bean needed to be
defined explicitly.

As the transaction is an important aspect of enterprise applications, let us understand how Spring Data JPA
supports transactions.

Spring data CRUD methods on repository instances are by default transactional.

For read operations, readOnly flag is set to true and all other operations are configured by applying
@Transactional with default transaction configuration.

Suppose there is a requirement to change the transaction configuration for a method declared in the
CustomerRepository interface. Simply re-declare the method as shown below:

1. public interface CustomerRepository extends


JpaRepository<Customer,Long>{
2. @Override
3. @Transactional(readOnly = true)
4. public List<Customer> findAll();
5. // Further query method declarations

6. }

Here, findAll() is annotated with @Transactional by setting the readOnly flag to true, this will override the
default behavior provided by Spring Data. We'll discuss more attributes of @Transacational annotation in
the upcoming topics.

Update Operation in Spring Data JPA


Now that you know, how to use @Query annotation for query operations.

Can @Query annotation be used for performing modification operations?

Yes, it can execute modifying queries such as update, delete or insert operations using @Query
annotation along with @Transactional and @Modifying annotation at query method.

Example: Interface with a method to update the name of a customer based on the customer's address.
1. public interface CustomerRepository extends
JpaRepository<Customer, Long> {
2. @Transactional
3. @Modifying(clearAutomatically = true)
4. @Query("update Customer c set c.name = ?1 where c.address =
?2")
5. void update(String name, String address);
6. }

7.

Let us now understand in detail, why there is a need for the following:

@Modifying: This annotation will trigger @Query annotation to be used for an update operation instead of
a query operation.

@Modifying(clearAutomatically = true): After executing modifying query, EntityManager might contain


unrequired entities. It is a good practice to clear the EntityManager cache automatically by
setting @Modifying annotation’s clearAutomatically attribute to true.

@Transactional: Spring Data provided CRUD methods on repository instances that support
transactional by default with read operation and by setting readOnly flag to true. Here, @Query is used for
an update operation, and hence we need to override default readOnly behavior to read/write by explicitly
annotating a method with @Transactional.

@Modifying: This annotation triggers the query annotated to a particular method as an updating query
instead of a selecting query. As the EntityManager might contain outdated entities after the execution of the
modifying query, we should clear it. This effectively drops all non-flushed changes still pending in the
EntityManager. If we don't wish the EnetiyManager to be cleared automatically we can set @Modifying
annotation's clearAutomatically attribute to false.

Fortunately, starting from Spring Boot 2.0.4.RELEASE, Spring Data added flushAutomatically flag to auto
flush any managed entities on the persistence context before executing the modifying query.

Thus, the safest way to use Modifying is:

1. @Modifying(clearAutomatically=true, flushAutomatically=true)

Now let's take a small scenario where we don't use these two attributes with @Modifying annotation:

Assume a Customer table with two columns name and active, exists in the database with only one row as
Tom, true.

Repository:

1. public interface CustomerRepository extends


JPARepository<Customer, Intger> {
2. @Modifying
3. @Query("delete Customer c where c.active=0")
4. public void deleteInActiveCustomers();
5.

6. }

In the above repository, @Modifying annotation is used without clearAutomatically


and flushAutomatically attributes. So let's visualize what happens when the Service call happens.

Visualization -1: If flushAutomatically attribute is not used in the Repository:

1. public class CustomerServiceImpl implements CustomerService {


2. Customer customerTom = customerRepository.findById(1); //
Stored in the First Level Cache
3. customerTom.setActive(false);
4. customerRepository.save(customerTom);
5.
6. customerRepository.deleteInActiveUsers();// By all means
it won't delete the customerTom
7.
8. /*customerTom still exist since customerTom with 'active'
attribute being set to false was not flushed into the database
when @Modifying kicks in*/

9. }

Visualization -2: If clearAutomatically attribute is not used in the Repository:

1. public class CustomerServiceImpl implements CustomerService {


2. Customer customerTom = customerRepository.findById(1); //
Stored in the First Level Cache
3. customerRepository.deleteInActiveCustomers(); // We think
that customerTom is deleted now
4.
System.out.println(customerRepository.findById(1).isPresent()) //
Will return TRUE
5. System.out.println(customerRepository.count()) // Will
return 1
6.
7. // TOM still exist in this transaction persistence context
8. // TOM's object was not cleared upon @Modifying query
execution
9. // TOM's object will still be fetched from First Level
Cache
10. /* clearAutomatically attribute takes care of doing the
clear part on the objects being modified for current transaction
persistence context*/

11. }
Custom Repository Implementation
So far, we have seen different approaches to create queries.

Sometimes, customization of a few complex methods is required. Spring easily support this, you can use
custom repository code and integrate it with Spring Data abstraction.

Let us look at how to define the custom repository in detail.

Example: Let us consider a customer search scenario wherein customer details needs to be fetched based
on name and address or gender or age.

Entity class Customer is shown below:

1. @Entity
2. public class Customer {
3.
4. @Id
5. private Long phoneNumber;
6. private String name;
7. private Integer age;
8. private Character gender;
9. private String address;
10. private Integer planId;
11. -------

12. }

The steps to implement the custom repository with a method to Retrieve customer records based on search
criteria are as follows:

Step 1: Define an interface and an implementation for the custom functionality.

1. public interface ICustomerRepository {


2.
3. public List<Customer> searchCustomer(String name, String addr,
Character gender, Integer age);
4. }

5.

Step 2: Implement this interface using repository class as shown below:

1. public class CustomerRepositoryImpl implements


ICustomerRepository{
2.
3. private EntityManagerFactory emf;
4.
5. @Autowired
6. public void setEntityManagerFactory(EntityManagerFactory emf) {
7. this.emf = emf;
8. }
9.
10. @Override
11. public List<Customer> searchCustomer(String name, String
address, Character gender, Integer age) {
12. EntityManager em = emf.createEntityManager();
13. CriteriaBuilder builder =
em.getCriteriaBuilder();
14.
15. CriteriaQuery<Customer> query =
builder.createQuery(Customer.class);
16. Root<Customer> root = query.from(Customer.class);
17.
18. Predicate cName = builder.equal(root.get("name"),
name);
19. Predicate cAddress =
builder.equal(root.get("address"), address);
20.
21. Predicate exp1 = builder.and(cName, cAddress);
22.
23. Predicate cGender =
builder.equal(root.get("gender"), gender);
24. Predicate cAge = builder.equal(root.get("age"),
age);
25.
26. Predicate exp2 = builder.or(cGender,cAge);
27.
28. query.where(builder.or(exp1, exp2));
29.
30. return
em.createQuery(query.select(root)).getResultList();
31. }

32.

Step 3: Define repository interface extending the custom repository interface as shown below:

1. public interface CustomerRepository extends


JpaRepository<Customer, Long>,ICustomerRepository{
2.
3. }

4.

Now, standard repository interface CustomerRepository extends both JpaRepository and the custom
interface(ICustomerRepository). Hence, all the Spring data provided default methods, as well as the custom
defined method(searchCustomer), will be accessible to the clients.

Data access layer of an application has the following files with dependencies is as shown below:
Best Practices - Spring Boot
Some of the best practices that need to be followed as part of the Quality and Security for Spring Boot
applications. These practices, when applied during designing and developing a Spring Boot
application, yields better performance.

Best Practices:

1. Use Spring Initializr for creating Spring Boot projects


2. Use the correct project Structure while creating Spring Boot projects
3. Choose Java-based configuration over XML based configuration

4. Use Setter injection for optional dependencies and Constructor injection for mandatory dependencies
5. Use @Service for Business Layer classes
6. Follow the Spring bean naming conventions while creating beans

Let us understand the reason behind these recommendations and their implications.

Note: For the demos already covered in the course, we would be applying these best practices.

You might also like