Java and Spring Data JPA: Easy SQL Data Access
Abstract
Presenter: Miya W. Longwe, MBA, MSE, Tech Lead, Staples, Inc, Framingham MA 01702
Accessing data repositories in various applications programming languages typically involves writing of tedious boilerplate lines of code. Some application development frameworks such as Spring have tried to make the experience more succinct by providing abstraction layers such as HibernateTemplate and JdbcTemplate, etc. Despite these APIs, the developers still spend a lot time writing repetitive code than concentrating on implementing business requirements. Developers at Spring, led by Oliver Gierke, introduced Spring Data JPA which “aims to significantly improve the implementation of data access layers by reducing the effort to the amount that's actually needed. As a developer you write your repository interfaces, including custom finder methods, and Spring will provide the implementation automatically”.
Spring Data JPA provides a powerful, out-of-the-box alternative to creating your own DAO framework. You declare custom repository operations on an interface, and the framework generates dynamic implementations (not code generation) automatically, based on conventions around method names. As part of the presentation, we'll also review a demo to look at Spring Java configuration (as opposed to XML configuration), and investigate the @Profile annotation – configuration details which may make life a bit easier in various ways when setting up unit testing of our repository classes, using out-of-the-box alternative to creating DAO framework, how to create custom repositories, pagination and support for custom queries among other features.
Presenter's Bio
Miya W. Longwe is a Senior Software Engineer and Tech Lead at Staples, Inc. where he is currently working on an initiative to re-platform the company’s ecommerce architecture to offer platform-driven, modular products that can be quickly customized, enhanced, and branded as needed.
Miya has been a software professional since 1997. His 16 years software development career includes working for large companies to small startups, building solutions for enterprises and consumers, working with a broad range of technologies.
Miya Longwe is a hands-on java developer. He believes that in order to be a relevant and effective software developer one needs to remain a deeply knowledgeable, up-to-date, and productive software developer. His research interests include model-driven engineering, domain specific languages, test driven development and project risk management.
Miya graduated from the University of Malawi (Lilongwe, Malawi) and has an MBA from the University of Wales Cardiff Business School (Wales, UK) and a Masters in Software Engineering from Brandeis University (MA, USA).
Occasionally, Miya can be spotted fishing the banks of the south shore (MA) with his two boys, William and Daniel.
4. Application Domain
Domain driven design has become a
ubiquitous approach to tackle
complex problem domains and build
a rich object model.
Implementing a data access layer of
an application has been cumbersome
for quite a while.
Too much boilerplate code has to be
written.
Code to execute simple queries as
well as perform pagination, auditing,
etc
5. Java DB Access – Accessor
Interface
public interface CustomerService {
Customer findById(Long id);
Customer save(Customer customer);
List<Customer> findAll();
List<Customer> findAll(int page, int pageSize);
...
}
6. Java DB Access –
The Boilerplate Code
/**
* Plain JPA implementation of {@link CustomerService}.
*
* @author Miya W Longwe
*/
@Repository
@Transactional(readOnly = true)
public class CustomerServiceImpl implements CustomerService {
@PersistenceContext
private EntityManager em;
@Override
public Customer findById(Long id) {
return em.find(Customer.class, id);
}
@Override
public List<Customer> findAll() {
return em.createQuery("select c from Customer c", Customer.class).getResultList();
}
……
}
7. Java DB Access – The Story
● JPA handles mechanics of ORM
● The catch:
– You are responsible for accessor
boilerplate code
● Using direct JDBC?
– More boilerplate code (think DAO
layer)
● What about Spring support?
– Makes things better (JdbcTemplate)
– Spring-Data eases the pain further
9. Spring-Data
Uses the Repository abstraction for
data access
Automation of data access
boilerplate code
Reduces level of efforts for accessor
code
Support for multiple data stores
including– JPA– Key-Value, column,
document, graph data stores(Redis,
Mongo, Neo4j, HBase)– Hadoop /
HDFS – Others
10. Spring-Data JPA Workflow
Define an Entity Class
Define a Repository interface with
data accessor methods
Then see you gator!
11. Define Your Entity
/**
* An entity class which contains the information of a single person.
* @author Miya W. Longwe
*/
@Entity
@Table(name = "persons")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "creation_time", nullable = false)
private Date creationTime;
@Column(name = "first_name", nullable = false)
private String firstName;
@Column(name = "last_name", nullable = false)
private String lastName;
@Column(name = "modification_time", nullable = false)
private Date modificationTime;
...}
12. Define The Repository
Interface
You provide a Java interface
– Attach an entity type along with key type
– CRUD/data accessor method signatures
Spring-Data can automatically derive
proper JPQL
In simpler cases, no additional code
required
Queries are derived from method
signatures
13. Repository Interface
* Specifies methods used to obtain and
modify person related information
* which is stored in the database.
* @author Miya W. Longwe
*/
public interface PersonRepository
extends JpaRepository<Person, Long> {
}
14. No More Boilerplate Code
It goes away (sort of) *
Spring-Data framework derives and
attaches JPQL (or specified query) at
load-time
16. Provided Repositories
Spring-Data JPA provides two
repositories
CrudRepository
– Long list of standard CRUD operations
provided
– findOne(), findAll(), save(), delete(),
exists(), etc
PagingAndSortingRepository
– Derived from CrudRepository
– Provides paginated repository
access methods
17. Configure Spring Framework
Specify your repository locations for
scanning
Spring will create proxy instances
for repositories
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http:/www.springframework.org/schema/beans"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<mvc:resources mapping="/static/**" location="/static/"/>
<mvc:default-servlet-handler/>
<!--
Configures Spring Data JPA and sets the base package of my DAOs.
-->
<jpa:repositories base-package="com.meetup.easydata.spring.datajpa.repository"/>
</beans>
18. Spring-Data Query Generation
Derived from method signatures
Parses method names for attributes and
keywords
Uses method parameters as query params
public interface UserRepository extends CrudRepository<User, Long> {
List<Customer> findByEmailAddressAndLastname(String emailAddress, String
lastname);
}
Select c from Customer where c.emailAddress = ?1
and c.lastName = ?2
19. Spring-Data
Method Name-to-JPQL Mapping
Method Name Generated JPQL
findByXxxAndYyy(aaa,
bbb)
... where t.xxx = ?1 and
t.yyy = ?2
findByXxxOrYyy(aaa,
bbb)
... where t.xxx = ?1 or
t.yyy = ?2
findByXxxStartingWith(a
aa)
('%' appended to param
value)
findByXxxNot(aaa) ... where t.xxx <> ?1
findByXxxIn(Collection<
E>aaa)
...where t.xxx in ?1
---and many more!
20. Spring-Data
Further Property Parsing Features
-Traversal can reach into nested properties
-Will do best effort using camelCase
-You can delineate properties using “_”
}
@Entity
public class User <Long> {
private ZiCode zicode;
--}
}
public interface UserRepository extends
CrudRepository<User, Long>{
...
User findByAddress_ZipCode(ZipCode zipCode);
21. @Query – Use Your Own
Query
• You don't like the derived query or want to do
something fancier?
● Use @Query notation to provide your own
● Support both JPQL or native SQL
● Still provides automatic proxy implementation
public interface UserRepository extends CrudRepository<User,
Long>{
...
@Query("select u from User u where u.firstname = ?1")
List<User> findByFirstname(String firstname);
@Query(value="SELECT FROM USERS WHERE
EMAIL_ADDRESS = ?1" nativeQuery=true)
User findByEmailAddress(String email);
...
22. @Query – Named Params
• Spring-Data JPA will use position for parameter binding
• You can also use named params instead
interface UserRepository extends CrudRepository<User,
Long>{
...
@Query("select u from User u where u.firstname = :name
or u.lastname = :name")
List<User> findByFirstnameOrLastname(@Param("name")
String name);
...
}
23. Result Pagination
• Seamlessly provides support for result set pagination
via Pageable Interface
• Define repository method with Pageable
• Call method with PageRequest class (or define your
own)
public interface ProductRepository extends CrudRepository<User, Long>{
...
Page<Product> findAll(Pageable pageable);
...
}
class ProductService {
Pageable pageable = new PageRequest(1, 20);
Page<Product> page = repository.findByDescriptionContaining(pageable);
}
24. Custom Repositories
• When Spring-Data JPA derived queries are not
• enough or you need additional logic
• Provide your own repository implementation
• A bean that lives in Spring Context
interface UserRepositoryCustom {
List<User> myCustomBatchOperation();
}
class UserRepositoryImpl implements UserRepositoryCustom {
@PersistenceContext
private EntityManager em;
public List<User> myCustomBatchOperation() {
CriteriaQuery<User> criteriaQuery = em.getCriteriaBuilder().createQuery(User.class);
return em.createQuery(criteriaQuery).getResultList();
}
}
25. Transaction Support
• Repository classes are transactional by default
• Reads are made readOnly
• Other methods are @Transactional by default
• Ability to override by providing your own
@Transactional demarcation
public interface UserRepository extends CrudRepository<User, Long>{
...
@Transactional(timeout=10)
@Modifying
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
User fixFirstNameByLastName(String firstname, String lastname);
...
}