UNIT III Material
UNIT III Material
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.
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.
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.
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:
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:
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 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:
Developing the persistence layer using Spring ORM JPA possess the following advantages:
So let's see additional configurations required for developing the repository layer of a Spring ORM JPA
application with Spring Boot.
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.
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.
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
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.
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.
InfyTel system's data access layer implementation using Spring Data JPA is as shown below:
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.
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:
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
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.
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.
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.
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.
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.
1. Starter Dependencies
2. Automatic Configuration
3. Spring Boot Actuator
4. Easy-to-use Embedded Servlet Container Support
There are multiple approaches to create a Spring Boot application. You can use any of the following
approaches to create the application:
In this course, you will learn how to use Spring Initializr for creating Spring Data JPA applications.
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:
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.
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.
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.
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.
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.
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.
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.
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
Note: findAll(Pageable page) and findAll(Sort sort) methods are internally provided by Spring.
To ask for the required page by specifying page size, a new PageRequest instance must be created.
Step 3: In the client code, pass the Pageable object to the repository method as a method parameter.
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
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"));
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:
What if one wants to query customer records based on the customer's address?
Query method names are derived by combining the property name of an entity with supported keywords
such as "findBy", "getBy", "readBy" or "queryBy".
2. findBy <DataMember><Op>
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.
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.
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:
Note:
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.
If a query is provided using more than one approach in an application. What is the default precedence given
by the Spring?
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.
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.
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.
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.
@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.
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.
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.
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:
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')
c");
2. query.executeUpdate();
Deleting a customer:
2. query.executeUpdate();
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')
CustomerEntity s")
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.
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.
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.
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.
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>
1. <dependency>
2. <groupId>mysql</groupId>
3. <artifactId>mysql-connector-java</artifactId>
4. <scope>runtime</scope>
5. </dependency>
Through declarative transaction management, update (Customer customer) method can be executed in
transaction scope using Spring.
11. }
This annotation will be identified automatically by Spring Boot if we have already included the spring-boot-
starter-data-jpa jar.
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.
11. }
There are different implementations available for PlatformTransactionManager to support different data
access technologies such as JDBC, JTA, Hibernate, JPA and so on.
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.
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:
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.
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.
@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.
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:
6. }
9. }
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.
Example: Let us consider a customer search scenario wherein customer details needs to be fetched based
on name and address or gender or age.
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:
5.
32.
Step 3: Define repository interface extending the custom repository interface as shown below:
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:
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.