spring data jpa介绍
首先了解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的实现产品。
spring data jpa
Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data JPA 可以极大提高开发效率!
添加spring-data-jpa的支持
<!--引入JPA的依赖关系-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
spring data jpa让我们解脱了DAO层的操作,基本上所有CRUD(增删改查)都可以依赖于它来实现
编写实体类
package com.mengma.tensquare_base.pojo;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "tb_label") //name = 表名
public class Label {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", updatable = false) // 与表字段一致 则可以不加
private String id;
private String labelname;
private String state;
private Long count;
private String recommend;
private Long fans;
public Label(String id, String labelname, String state, Long count, String recommend, Long fans) {
this.id = id;
this.labelname = labelname;
this.state = state;
this.count = count;
this.recommend = recommend;
this.fans = fans;
}
public Label() {
super();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id == null ? null : id.trim();
}
public String getLabelname() {
return labelname;
}
public void setLabelname(String labelname) {
this.labelname = labelname == null ? null : labelname.trim();
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state == null ? null : state.trim();
}
public Long getCount() {
return count;
}
public void setCount(Long count) {
this.count = count;
}
public String getRecommend() {
return recommend;
}
public void setRecommend(String recommend) {
this.recommend = recommend == null ? null : recommend.trim();
}
public Long getFans() {
return fans;
}
public void setFans(Long fans) {
this.fans = fans;
}
}
编写Repository接口
//此接口不需要添加注解
//当需要条件查询时,需要继承JpaSpecificationExecutor
public interface LabelDao extends JpaRepository<Label,String>,JpaSpecificationExecutor<Label> {
List<Label> findAllByRecommend(String recommend);
List<Label> findAllByState(String state);
}
编写实现层
package com.mengma.tensquare_base.service;
import com.mengma.common.utils.UUIDUtil;
import com.mengma.tensquare_base.dao.LabelDao;
import com.mengma.tensquare_base.pojo.Label;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* @author Administrator
* @Title: LabelRepositoryService
* @ProjectName tensquare_abu
* @Description: TODO
* @date 2019/1/11 0:32
*/
@Service
public class LabelRepositoryService {
@Autowired
private LabelDao labelDao;
public Label insert(Label label){
String id = UUIDUtil.getOrderIdByUUId();
label.setId(id);
// 新增
return labelDao.save(label);
}
public List<Label> getList(){
// 查询所有
return labelDao.findAll();
}
public List<Label> findByRecommend(String recommend){
// 根据条件查询
return labelDao.findAllByRecommend(recommend);
}
public List<Label> findByState(String state){
return labelDao.findAllByState(state);
}
public Label findById(String labelId){
// 根据id 查询
return labelDao.findById(labelId).get();
}
public Label update(Label label){
// 修改 save 即可做新增 也可做修改 是根据id进行判断 如果通过id查询数据库没有数据 则进行新增 反之
return labelDao.save(label);
}
public void delete(String labelId){
// 删除
labelDao.deleteById(labelId);
}
public List<Label> pageSearch(Label label){
// 不带条件的分页
return labelDao.findAll(new Specification<Label>() {
//root: 根对象 也就是要把条件封装到那个对象
//query: 封装的是查询的关键字 比如 group by ,order by 等
//criteriaBuilder: 用来封装条件对象 如果直接返回null 表示不需要任何条件
@Override
public Predicate toPredicate(Root<Label> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
List<Predicate> list = new ArrayList<>();
if (!StringUtils.isBlank(label.getLabelname())) {
Predicate labelname = criteriaBuilder.like(root.get("labelname").as(String.class), "%" + label.getLabelname() + "%");
list.add(labelname);
}
if (!StringUtils.isBlank(label.getState())) {
Predicate state = criteriaBuilder.equal(root.get("state").as(String.class), label.getState());
list.add(state);
}
if (!StringUtils.isBlank(label.getRecommend())) {
Predicate recommend = criteriaBuilder.equal(root.get("recommend").as(String.class), label.getRecommend());
list.add(recommend);
}
//criteriaBuilder.and(predicates数组) 由于predicates的数组长度未定 因此上面先定义用集合接收 然后在转为数组
Predicate[] predicates = new Predicate[list.size()];
predicates = list.toArray(predicates);
return criteriaBuilder.and(predicates);//相当于 where loginname like '%java%' and state="1"
}
});
}
public Page<Label> page(Integer page, Integer size, Label label){
Pageable pageable = PageRequest.of(page-1,size);
// 带条件的分页查询
return labelDao.findAll(new Specification<Label>() {
//root: 根对象 也就是要把条件封装到那个对象
//query: 封装的是查询的关键字 比如 group by ,order by 等
//criteriaBuilder: 用来封装条件对象 如果直接返回null 表示不需要任何条件
@Override
public Predicate toPredicate(Root<Label> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
List<Predicate> list = new ArrayList<>();
if (!StringUtils.isBlank(label.getLabelname())) {
Predicate labelname = criteriaBuilder.like(root.get("labelname").as(String.class), "%" + label.getLabelname() + "%");
list.add(labelname);
}
if (!StringUtils.isBlank(label.getState())) {
Predicate state = criteriaBuilder.equal(root.get("state").as(String.class), label.getState());
list.add(state);
}
if (!StringUtils.isBlank(label.getRecommend())) {
Predicate recommend = criteriaBuilder.equal(root.get("recommend").as(String.class), label.getRecommend());
list.add(recommend);
}
//criteriaBuilder.and(predicates数组) 由于predicates的数组长度未定 因此上面先定义用集合接收 然后在转为数组
Predicate[] predicates = new Predicate[list.size()];
predicates = list.toArray(predicates);
return criteriaBuilder.and(predicates);//相当于 where loginname like '%java%' and state="1"
}
},pageable);
}
}
package com.mengma.tensquare_base.controller;
import com.mengma.common.VO.PageResult;
import com.mengma.common.commons.ServerResponse;
import com.mengma.tensquare_base.dao.LabelDao;
import com.mengma.tensquare_base.pojo.Label;
import com.mengma.tensquare_base.service.LabelRepositoryService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.*;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
/**
* @author Administrator
* @Title: LabelController
* @ProjectName tensquare_abu
* @Description: TODO
* @date 2019/1/10 15:17
*/
@RestController
@RequestMapping("/")
public class LabelController {
@Autowired
private LabelRepositoryService labelRepositoryService;
/**
* @Description: 增加标签
* @Param:
* @return:
* @Author: ABU
* @Date: 2019/1/10
*/
@PostMapping("label")
public ServerResponse insert(@RequestBody Label label){
Label insert = labelRepositoryService.insert(label);
if(insert==null){
return ServerResponse.createByErrorMessage("添加失败");
}
return ServerResponse.createByflagMessage("添加成功");
}
@GetMapping("label")
public ServerResponse getLists(){
return ServerResponse.createByflag(labelRepositoryService.getList());
}
@GetMapping("label/toplist")
public ServerResponse topLists(){
return ServerResponse.createByflag(labelRepositoryService.findByRecommend("1"));
}
@GetMapping("label/list")
public ServerResponse stateLists(){
return ServerResponse.createByflag(labelRepositoryService.findByState("1"));
}
@GetMapping("label/{labelId}")
public ServerResponse getById(@PathVariable String labelId){
return ServerResponse.createByflag(labelRepositoryService.findById(labelId));
}
@PutMapping("/label/{labelId}")
public ServerResponse update(@PathVariable String labelId,
@RequestBody Label label){
//sava 既可以做保存 又可以做修改 根据传入的类的id 进行查询,没有就新增 反之
label.setId(labelId);
Label save = labelRepositoryService.update(label);
if (save==null){
return ServerResponse.createByErrorMessage("失败");
}
return ServerResponse.createByflagMessage("成功!");
}
@DeleteMapping("label/{labelId}")
public ServerResponse delete(@PathVariable String labelId){
labelRepositoryService.delete(labelId);
return ServerResponse.createByflagMessage("成功!");
}
@PostMapping("label/search")
public ServerResponse pageSearch(@RequestBody Label label){
return ServerResponse.createByflag(labelRepositoryService.pageSearch(label));
}
@PostMapping("label/search/{page}/{size}")
public ServerResponse page(@PathVariable Integer page,
@PathVariable Integer size,
@RequestBody Label label){
Page<Label> page1 = labelRepositoryService.page(page, size, label);
PageResult pageResult = new PageResult();
pageResult.setTotal(page1.getTotalElements());
pageResult.setRows(page1.getContent());
return ServerResponse.createByflag(pageResult);
}
}
在此处介绍一下上面提到的自定义Repository继承的两个接口,如果你的查询列表是没有查询条件,只是列表展示和分页,只需继承JpaRepository接口即可,但是如果你的查询列表是带有多个查询条件的话则需要继承JpaSpecificationExecutor接口,这个接口里面定义的多条件查询的方法。当然不管继承哪个接口,当你做分页查询时,都是需要调用findAll方法的,这个方法是jap定义好的分页查询方法。
下面介绍一下一些简单的默认查询
自定义简单查询
自定义的简单查询就是根据方法名来自动生成SQL,主要的语法是
findXXBy,readAXXBy,queryXXBy,countXXBy, getXXBy后面跟属性名称:
也使用一些加一些关键字 And、 Or
User findByUserNameOrEmail(String username, String email);
修改、删除、统计也是类似语法
Long deleteById(Long id);
Long countByUserName(String userName)
基本上SQL体系中的关键词都可以使用,例如:LIKE、 OrderBy。
List<User> findByEmailLike(String email);
List<User> findByUserNameOrderByEmailDesc(String email);
具体的关键字,使用方法和生产成SQL如下表所示
image.pngimage.png
复杂查询
在实际的开发中我们需要用到分页、删选、连表等查询的时候就需要特殊的方法或者自定义SQL
分页查询
分页查询在实际使用中非常普遍了,spring data jpa
已经帮我们实现了分页的功能,在查询的方法中,需要传入参数Pageable
,当查询中有多个参数的时候 Pageable
建议做为最后一个参数传入
Page<User> findALL(Pageable pageable);
Page<User> findByUserName(String userName,Pageable pageable);
Pageable
是spring封装的分页实现类,使用的时候需要传入页数、每页条数和排序规则
@Test
public void testPageQuery() throws Exception {
int page=1,size=10;
Sort sort = new Sort(Direction.DESC, "id");
Pageable pageable = new PageRequest(page, size, sort);
userRepository.findALL(pageable);
userRepository.findByUserName("testName", pageable);
}
限制查询
有时候我们只需要查询前N个元素,或者支取前一个实体。
User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);
自定义SQL查询
其实Spring data 觉大部分的SQL都可以根据方法名定义的方式来实现,但是由于某些原因我们想使用自定义的SQL来查询,spring data也是完美支持的;在SQL的查询方法上面使用 @Query
注解,如涉及到删除和修改在需要加上@Modifying
.也可以根据需要添加 @Transactional
对事物的支持,查询超时的设置等
@Modifying
@Query("update User u set u.userName = ?1 where c.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);
网友评论