美文网首页
Spring data jpa 使用

Spring data jpa 使用

作者: Pts | 来源:发表于2019-01-11 10:46 被阅读0次

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.png
image.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);

相关文章

网友评论

      本文标题:Spring data jpa 使用

      本文链接:https://www.haomeiwen.com/subject/qautdqtx.html