Spring data jpa 使用

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);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容