一、spring data JPA介绍
(1)什么是JPA?
JPA(Java Persistence API)是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据。他的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate,TopLink,JDO等ORM框架各自为营的局面。值得注意的是,JPA是在充分吸收了现有Hibernate,TopLink,JDO等ORM框架的基础上发展而来的,具有易于使用,伸缩性强等优点。从目前的开发社区的反应上看,JPA受到了极大的支持和赞扬,其中就包括了Spring与EJB3.0的开发团队。注意:JPA是一套规范,不是一套产品,那么像Hibernate,TopLink,JDO他们是一套产品,如果说这些产品实现了这个JPA规范,那么我们就可以叫他们为JPA的实现产品。
(2)spring data jpa
Spring Data JPA 是Spring基于ORM 框架、JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data JPA 可以极大提高开发效率!spring data jpa让我们解脱了DAO层的操作,基本上所有CRUD都可以依赖于它来实现。
二、基本查询
基本查询也分为两种,一种是spring data默认已经实现,一种是根据查询的方法来自动解析成SQL。
(1)预先生成方法
spring data jpa 默认预先生成了一些基本的CURD的方法,例如:增、删、改等等。
/**
* Dao层
* 继承 JpaRepository 就能够使用提供的默认方法
* @author 游王子
*/
public interface UserRepository extends JpaRepository<User, Long> {
}
测试:
@Test
public void test() {
User user = new User();
user.setNickName("bb123456");
/*
* 按例查询(QBE)是一种用户界面友好的查询技术。
* 它允许动态创建查询,并且不需要编写包含字段名称的查询。
* 实际上,按示例查询不需要使用特定的数据库的查询语言来编写查询语句。
*/
Example<User> example = Example.of(user);
List<User> findAll = userRepository.findAll();
findAll.forEach(s->System.out.println(s));
Optional<User> findById = userRepository.findById(1l);
System.out.println(findById);
// userRepository.save(user);
// userRepository.delete(user);
long count = userRepository.count();
Assert.assertEquals(3, count);
boolean exists = userRepository.exists(example);
Assert.assertTrue(exists);
}
(2)自定义简单查询
自定义的简单查询就是根据方法名来自动生成SQL,主要的语法是findXXBy,readAXXBy,queryXXBy,countXXBy, getXXBy后面跟属性名称:
public interface UserRepository extends JpaRepository<User, Long> {
User findByUserName(String userName);
// 也使用一些加一些关键字And、 Or。
User findByUserNameOrEmail(String username, String email);
//修改、删除、统计也是类似语法。
void deleteById(Long id);
Long countByUserName(String userName);
// 基本上SQL体系中的关键词都可以使用,例如:LIKE、 IgnoreCase、 OrderBy。
List<User> findByEmailLike(String email);
User findByUserNameIgnoreCase(String userName);
List<User> findByUserNameOrderByEmailDesc(String email);
}
具体的关键字,使用方法和生产成SQL如下表所示:
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age ⇐ ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull | findByAgeIsNull | … where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | … where x.age not in ?1 |
TRUE | findByActiveTrue() | … where x.active = true |
FALSE | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
三、复杂查询
在实际的开发中我们需要用到分页、删选、连表等查询的时候就需要特殊的方法或者自定义SQL
(1)分页查询
分页查询在实际使用中非常普遍了,spring data jpa已经帮我们实现了分页的功能,在查询的方法中,需要传入参数Pageable ,当查询中有多个参数的时候Pageable建议做为最后一个参数传入
@Query(value = "SELECT * FROM USER"
, countQuery = "SELECT count(*) FROM USER"
, nativeQuery = true)
Page<User> findALL(Pageable pageable);
Pageable 是spring封装的分页实现类,使用的时候需要传入页数、每页条数和排序规则
@Test
public void test() {
// PageRequest.of(page,size,sort)
Pageable pageable=PageRequest.of(0,3,Sort.by(Direction.DESC,"id"));
Page<User> findAll = userRepository.findALL(pageable);
List<User> content = findAll.getContent();
}
返回值Page对象常用方法
Page对象常用方法:
getTotalPages() 总共有多少页
getTotalElements() 总共有多少条数据
getNumber() 获取当前页码
getSize() 每页指定有多少元素
getNumberOfElements() 当前页实际有多少元素
hasContent() 当前页是否有数据
getContent() 获取当前页中所有数据(List<T>)
getSort() 获取分页查询排序规则
isFirst() 当前页是否是第一页
isLast() 当前页是否是最后一页
hasPrevious() 是否有上一页
hasNext() 是否有下一页
(2)限制查询
有时候我们只需要查询前N个元素,或者只取前一个实体。
// 查询id最大的用户
User findFirstByOrderByIdDesc();
// 查询id最小的前两名用户
List<User> findFirst2ByOrderByIdAsc();
(3)自定义SQL查询
其实Spring data 觉大部分的SQL都可以根据方法名定义的方式来实现,但是由于某些原因我们想使用自定义的SQL来查询,spring data也是完美支持的;在SQL的查询方法上面使用@Query注解,如涉及到删除和修改在需要加上@Modifying.也可以根据需要添加 @Transactional 对事物的支持,查询超时的设置等
@Modifying
@Query("update User u set u.userName = ?1 where u.id = ?2")
int modifyByIdAndUserId(String userName, Long id);
@Transactional
@Modifying
@Query("delete from User where id = ?1")
void deleteByUserId(Long id);
@Transactional(timeout = 10)
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
(4)多表查询
多表查询在spring data jpa中可以利用hibernate的级联查询来实现。