Sunteți pe pagina 1din 26

Easy Data with

Spring-Data JPA
Miya W. Longwe, Tech Lead, Staples Inc.
January 07, 2014
Java Meetup Group, Cambridge, MA , USA

Agenda
Java DB Access Ordeal

Enter Spring-Data

Spring-Data JPA Features


Code Demo

Q and A

Java DB Access
The Developers Holy Pilgrim!

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

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);
...
}

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();
}

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

Spring-Data to the Rescue!

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

Spring-Data JPA Workflow


Define an Entity Class
Define a Repository interface with
data accessor methods
Then see you gator!

Define Your Entity


/**
* An entity class w hich contains the inform ation of a single person.
* @ au th or M iya W . Lon g w e
*/
@ Entity
@ Table(nam e = "persons")
p u b lic class P erson {
@ Id
@ G eneratedValue(strategy = G enerationType.AU TO )
p rivate Lon g id ;
@ Colum n(nam e = "creation_tim e", nullable = false)
p rivate D ate creation Tim e;
@ Colum n(nam e = "fi
rst_nam e", nullable = false)
p rivate S trin g f i
rstN am e;
@ Colum n(nam e = "last_nam e", nullable = false)
p rivate S trin g lastN am e;
@ Colum n(nam e = "m odifi
cation_tim e", nullable = false)
p rivate D ate m od if i
cation Tim e;
...}

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

Repository Interface
* Specifi
es m ethods used to obtain and
m odify person related inform ation
* w hich is stored in the database.
* @ au th or M iya W . Lon g w e
*/
p u b lic in terface P erson R ep ository
exten d s Jp aR ep ository< P erson , Lon g >
{
}

No More Boilerplate Code


It goes away (sort of) *
Spring-Data framework derives and
attaches JPQL (or specified query) at
load-time

Spring-Data Features

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

Configure Spring Framework


Specify your repository locations for
scanning

Spring will create proxy instances


for repositories

< ?xm lversion= "1.0" encoding= "U TF-8"?>


< beans xm lns= "http:/w w w .springfram ew ork.org/schem a/beans"
xm lns:jpa= "http://w w w .springfram ew ork.org/schem a/data/jpa"
xm lns:m vc= "http://w w w .springfram ew ork.org/schem a/m vc"
xm lns:xsi= "http://w w w .w 3.org/2001/XM LSchem a-instance"
xsi:schem aLocation= "
http://w w w .springfram ew ork.org/schem a/beans
http://w w w .springfram ew ork.org/schem a/beans/spring-beans-3.1.xsd
http://w w w .springfram ew ork.org/schem a/data/jpa
http://w w w .springfram ew ork.org/schem a/data/jpa/spring-jpa-1.0.xsd
http://w w w .springfram ew ork.org/schem a/m vc
http://w w w .springfram ew ork.org/schem a/m vc/spring-m vc-3.1.xsd">
< m vc:resources m apping= "/static/**" location= "/static/"/>
< m vc:default-servlet-handler/>
< !-Confi
g ures Spring D ata JPA and sets the base package of m y D AO s.
-->
< jpa:repositories base-package= "com .m eetup.easydata.spring.datajpa.repository"/>
< /beans>

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

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!

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 U ser < Long> {
private ZiC ode zicode;
--}
}
public interface U serRepository extends
CrudRepository< U ser, Long> {
...
U ser fi
n dByAddress_ZipCode(ZipCode
zipCode);

@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
public interface U serRepository extends
implementation
CrudRepository< U ser, Long> {
...
@ Q uery("select u from U ser u w here u.fi
rstnam e = ?1")
List< U ser> fi
n dByFirstnam e(String fi
rstnam e);
@ Q uery(value= "SELECT FRO M U SERS W H ERE
EM AIL_AD D RESS = ?1" nativeQ uery= true)
U ser fi
ndByEm ailAddress(String em ail);

...

@Query Named Params


Spring-Data JPA will use position for parameter binding
You can also use named params instead
interface U serRepository extends
CrudRepository< U ser, Long> {
...
@ Q uery("select u from U ser u w here u.fi
rstnam e
= :nam e or u.lastnam e = :nam e")
List< U ser>
fi
n dByFirstnam eO rLastnam e(@ Param ("nam e")
String nam e);
...
}

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< U ser,
Long> {
...
Page< Product> fi
ndAll(Pageable pageable);
...
}
class ProductService {
Pageable pageable = new PageRequest(1, 20);
Page<Product> page = repository.findByDescriptionContaining(pageable);
}

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 U serRepositoryCustom {
List< U ser> m yCustom BatchO peration();
}
class U serRepositoryIm plim plem ents U serRepositoryCustom {
@ PersistenceC ontext
private EntityM anager em ;
public List< U ser> m yC ustom BatchO peration() {
CriteriaQ uery< U ser> criteriaQ uery =
em .getCriteriaBuilder().createQ uery(U ser.class);
return em .createQ uery(criteriaQ uery).getResultList();
}
}

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 U serRepository extends CrudRepository< U ser,
Long> {
...
@ Transactional(tim eout= 10)
@ M odifying
@ Q uery("update U ser u set u.fi
rstnam e = ?1 w here
u.lastnam e = ?2")
U ser fi
xFirstN am eByLastN am e(String fi
rstnam e, String
lastnam e);
...
}

Code Demo

S-ar putea să vă placă și