springboot专题复习 spring data jpa复习

spring data jpa复习

本人最近一直在为秋招和明年的春招做准备,目前在复习一些框架的基础知识,ORM框架有很多种,本人比较常用的mybatis,所以在mybatis上会加深到对一些源码的认识,但是对于jpa,我不是很经常用,只是对其使用做一个基本的整理,本文的目的就是如此,今后有时间会对jpa的内部原理进行剖析,如果有在一起为明年春招做准备的小伙伴,欢迎互粉呀,共同进退

一,spring data jpa是什么?

聊到spring data jpa 就不得不从jpa聊起来了

1.什么是jpa?

jpa就是实现了ORM思想的一种规范。

何为orm思想?

orm思想简单来说就是,操作实体类对象就相当于操作数据库表,通过对实体类对象的操作完成对数据库表的操作。将实体类和数据库表,实体类属性和数据库表字段建立起了映射关系。

有了orm思想自然会有实现orm思想的框架

实现了orm思想的框架就有hibernate,Toplink等等,那么,jpa规范也就相应出现了,SUN公司推出的一套基于ORM的规范,内部是由一系列的接口和抽象类构成,框架提供实现

2.jpa规范

)

3.何为spring data jpa?

Spring Data Jpa则是在JPA之上添加另一层抽象(Repository层的实现),极大地简化持久层开发及ORM框架切换的成本。相当于在jpa规范上的一层封装

二,spring data jpa使用

下边的示例是基于springboot2.x ,spring data jpa2.1.5实现,是一个maven工程

maven依赖

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
    </dependencies>

application.properties

##########################################
spring.datasource.url=jdbc:mysql://localhost:3306/employee?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
##########################################
###spring JPA配置信息
###spring.jpa.database指定目标数据库.
spring.jpa.database = MYSQL
###spring.jps.show-sq:是否显示sql语句
spring.jpa.show-sql = true
###spring.jpa.hibernate.ddl-auto指定DDL mode (none, validate, update, create, create-drop). 当使用内嵌数据库时,默认是create-drop,否则为none.
spring.jpa.hibernate.ddl-auto = update
###spring.jpa.hibernate.naming-strategy指定命名策略
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
###指定方言
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

关于spring.jpa.hibernate.ddl-auto

  • update:原来数据库表存在则不删除,每次项目启动运行执行数据库表更新(一般推荐update)

  • create:不管原来数据库表存在与否,每次项目启动运行都会重新建表,有表的则删除后重新建表

  • none:什么都不干

  • create-drop:每次运行程序时会先创建表结构,然后待程序结束时清空表

1.建立实体和表,实体属性和表字段的映射关系

//标识数据库实体
@Entity
@Table(name = "tb_jpatest")//name:数据库表名
@Data
public class JpaTest {

    //指定主键和主键生成策略
    /**
     * jpa自带主键生成策略
     *      - TABLE : 使用一个特定的数据库表格来保存主键值
     *      - SEQUENCE : 根据底层数据库的序列来生成主键,条件是数据库支持序列。
     *                   这个值要与generator一起使用,generator 指定生成主键使用的生成器(可能是orcale中自己编写的序列)
     *      - IDENTITY :  主键由数据库自动生成(主要是支持自动增长的数据库,如mysql)
     *      - AUTO: 主键由程序控制,也是GenerationType的默认值
     */
    @Id
    //@GenericGenerator(name = "id",strategy = "uuid")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    //标识列属性
    @Column(name = "test_id")
    private int testId;

    @Column(name = "info",nullable = false,length = 255)
    private String info;

    @Column(name = "gmt_create")
    private Date gmtCreate;

    //标识不是数据库的列,默认是 @Basic
    @Transient
    @Override
    public String toString() {
        return "JpaTest{" +
                "id=" + id +
                ", testId=" + testId +
                ", info='" + info + '\'' +
                ", gmtCreate=" + gmtCreate +
                '}';
    }
}

2.CRUD操作

执行crud操作,我们需要先建立一个自己的dao层,但是,这个dao层不同于原来mybatis需要自己编写代码,和mapper.xml,我们可以在spring data jpa实现0sql,0代码

public interface JpaTestDao extends JpaRepository<JpaTest,Long>, JpaSpecificationExecutor<JpaTest> {

    /**
     *  JpaRepository<T,D>     --> 封装了基本的CRUD操作
     *        需要提供两个泛型   - T:操作的实体类类型
     *                         -  D:实体类主键的类型
     *
     *  JpaSpecificationExecutor<T>   ---> 封装了复杂查询(分页,排序等等)
     *         只需要提供一个泛型    - T:操作的实体类类型
     *
     */
}

在这里插入图片描述

所以我们只需要继承JpaRepository,JpaSpecificationExecutor便可以实现大多数的增删改查操作了

1.查询
基于内部api的查询

实现了这两个接口,基本上jpa已经为我们提供了很多内部对数据库表crud的api了

在这里插入图片描述

save()保存或更新:

  • save()方法默认jpa提供得save方法当不提供id时就是执行insert操作
  • save()默认jpa提供的save方法当提供id时就是执行update操作
    @Autowired
    private JpaTestDao jpaTestDao;

    /**
     * save()保存
     * @param jpaTest
     */
    @Override
    public void insert(JpaTest jpaTest) {
        jpaTest.setGmtCreate(new Date());
        jpaTest.setInfo("test1");
        //save()方法默认jpa提供得save方法当不提供id时就是执行insert操作
        jpaTestDao.save(jpaTest);
    }

    /**
     * save()更新
     * @param jpaTest
     */
    @Override
    public void update(JpaTest jpaTest) {
        jpaTest.setId((long)1);
        jpaTest.setInfo("update");
        //save()默认jpa提供的save方法当提供id时就是执行update操作
        jpaTestDao.save(jpaTest);
    }

根据主键查询

        //findById()根据主键查询
        Optional<JpaTest> jpaTest = jpaTestDao.findById((long)2);
        System.out.println(jpaTest.toString());
        System.out.println("查询所有");
        //查询所有
        List<JpaTest> list = jpaTestDao.findAll();
        for(JpaTest j : list){
            System.out.println(j);
        }

但是这些内部api大多都是基于主键的操作,很多时候在开发中,并不能满足需求,所以我们需要一些复杂查询。

复杂查询

基于Specification接口的复杂查询

        jpaTestDao.findAll(new Specification<JpaTest>() {
            //实现该接口
            @Override
            public Predicate toPredicate(Root<JpaTest> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                //构造查询条件和查询方式
                return null;
            }
        })

参数讲解:

  • root:查询需要比较的对象属性

                    //获取查询需要比较的属性
                    Path<Object> testId = root.get("testId");//实体类属性
    

    相当于sql语句中的where后边跟的字段

    select * from tb where testId = ''
    
  • criteriaQuery:一般很少用到

  • criteriaBuilder:查询构造器,构造查询方式

                    //构造查询方式
                        // 1.第一个参数:需要比较的属性(path对象)
                        // 2.第二个参数:该比较的属性的取值,这里可以实现动态的传参
                    Predicate p1 = criteriaBuilder.equal(testId,"1");
    

    返回的Predicate就是最终的返回值

    模糊查询需要注意,不同于equals,like在构造查询方式时需要将path对象利用path.as(属性对应类型的字节码)转化才行

                    //模糊查询需要注意
                        //模糊查询不同于equals,
                            // - equals在构造查询方式时直接传递path对象即可
                            // - like在构造查询方式时需要将path对象利用path.as(属性对应类型的字节码)转化才行
                    Predicate p3 = criteriaBuilder.like(info.as(String.class),"1%");
    

    也可以拼接多个条件,有and,or等等

                    //拼接查询条件
                        //and() -- 与,是可变参数
                        //or() -- 或,也是可变参数
                    Predicate p4 = criteriaBuilder.and(p1,p3);
    

示例:

        System.out.println("复杂查询");
        //复杂查询
        List<JpaTest> list1 = jpaTestDao.findAll(new Specification<JpaTest>() {
            /**
             * 相当于mybatis中逆向工程出来的example的条件查询,构造查询条件
             * @param root  【查询需要比较的对象属性】
             * @param criteriaQuery    自定义查询方式
             * @param criteriaBuilder  【查询条件】 查询的构造器,封装了很多查询条件
             * @return
             */
            @Override
            public Predicate toPredicate(Root<JpaTest> root, CriteriaQuery<?> criteriaQuery,
                                         CriteriaBuilder criteriaBuilder) {
                //获取查询需要比较的属性
                Path<Object> testId = root.get("testId");
                //构造查询方式
                    // 1.第一个参数:需要比较的属性(path对象)
                    // 2.第二个参数:该比较的属性的取值,这里可以实现动态的传参
                Predicate p1 = criteriaBuilder.equal(testId,"1");

                //多条件拼接
                Path<Object> info = root.get("info");
                //Predicate p2 = criteriaBuilder.equal(info,"1");

                //模糊查询需要注意
                    //模糊查询不同于equals,
                        // - equals在构造查询方式时直接传递path对象即可
                        // - like在构造查询方式时需要将path对象利用path.as(属性对应类型的字节码)转化才行
                Predicate p3 = criteriaBuilder.like(info.as(String.class),"1%");
                //拼接查询条件
                    //and() -- 与,是可变参数
                    //or() -- 或,也是可变参数
                Predicate p4 = criteriaBuilder.and(p1,p3);
                return p4;
            }
        });
        for(JpaTest j : list1){
            System.out.println(j);
        }

排序

排序主要用到Sort对象,实例化sort对象时需要传递两个参数

  • 确定倒序还是正序:

    Sort.Direction.ASC:正序
    Sort.Direction.ASC:正序
    
  • 第二参数就是确定排序的根据属性,就是根据哪个字段排序的意思,是一个可变参数,可传递多个

    Sort sort = new Sort(Sort.Direction.ASC,"id");
    

    示例:

        System.out.println("复杂查询 + 排序");
        //复杂查询 + 排序
        //排序对象
            //需要传递两个参数才能实例化sort对象
            // - 第一个参数:正序还是倒序
                    // Sort.Direction.ASC:正序
                    // Sort.Direction.ASC:正序
            // - 第二个参数:排序的属性
                    //该参数也是一个可变参数,可以有多个排序字段
        Sort sort = new Sort(Sort.Direction.ASC,"id");
        List<JpaTest> list2 = jpaTestDao.findAll(sort);
        for(JpaTest j : list2){
            System.out.println(j);
        }

分页

分页主要用到Pageable对象,实例化该对象时需要指定两个参数:

  • page:当前查询的页数,从0开始(即,你要查的是哪一页)
  • size:每页的结果数
Pageable pageable = new PageRequest(0,2);

示例:

        //复杂查询 + 分页
        System.out.println("复杂查询 + 分页");
        //分页接口pageable实现类PageRequest(page,size)
            // 第一个参数:page:当前查询的页数,从0开始(即,你要查的是哪一页)
            // 第二个参数:size:每页的结果数
        Pageable pageable = new PageRequest(0,2);
        Page<JpaTest> page = jpaTestDao.findAll(pageable);
        //得到总条数
        System.out.println(page.getTotalElements());
        //得到数据集合的列表
        System.out.println(page.getContent());
        //得到总页数
        System.out.println(page.getTotalPages());
        //以上的分页和排序都可以用在findAll()方法中传递
基于jpql的查询

jpql与sql的区别

jpql与SQL的区别就是SQL是面向对象关系数据库,他操作的是数据表和数据列,而jpql操作的对象是实体对象和实体属性

除了select * 不能直接写从from开始之外,其他都可以直接写,类似sql

关于sql参数:

  • 默认按照顺序拼接

  • 也可以 ?0:表示第一个参数。?1:表示第二个参数,依次类推

public interface JpaTestDao extends JpaRepository<JpaTest,Long>, JpaSpecificationExecutor<JpaTest> {

    /**
     *  JpaRepository<T,D>     --> 封装了基本的CRUD操作
     *        需要提供两个泛型   - T:操作的实体类类型
     *                         -  D:实体类主键的类型
     *
     *  JpaSpecificationExecutor<T>   ---> 封装了复杂查询(分页,排序等等)
     *         只需要提供一个泛型    - T:操作的实体类类型
     *
     */

    // jpql查询 --->可以用来进行复杂查询

    //支持jpql查询语句。
        //  基于注解的面向对象查询查询语句
        //  除了select * 不能直接写从from开始之外,其他都可以直接写,类似sql
        //  关于sql参数:
            // 默认按照顺序拼接
            // 也可以 ?0:表示第一个参数。?1:表示第二个参数,依次类推
    @Query(value = "from JpaTest where info = ?0")
    List<JpaTest> selectJpaTestByInfo(String info);

    @Query(value = "from JpaTest  where info = ?0 and id = ?1")
    List<JpaTest> selectJpaTestByInfoAndId(String info,int id);

    //更新(增删改)语句需要@Modifying注解配合,其他规则一致
    @Query(value = "update JpaTest set info = ?0 where id = ?1")
    @Modifying
    int updateJpaTest(String info,int id);

    //也可以编写原生sql。注解属性native = true即可
}
基于方法名称规则查询

格式

findBy + 查询比较属性 + and/or(查询方式)+查询比较属性 + and/or等等(查询方式)+查询比较属性 .....

示例:

    //基于方法名称规则的查询
    //类似这种,以findBy 开头:
            // findBy + 查询比较属性 + and/or(查询方式)+查询比较属性 + and/or等等(查询方式)+查询比较属性 .....
    List<JpaTest> findByTestIdAndInfo(String testId,String info);
2.更新(增删改)

默认提供的api的删除都是根据主键来执行的,先查询,在删除

User user = new User();
user.setId(21);
user.setName("王二");
/**
 * 删除都是根据主键删除
 */
//删除单条,根据主键值
userRepository.delete(20);
//删除全部,先findALL查找出来,再一条一条删除,最后提交事务
userRepository.deleteAll();
//删除全部,一条sql
userRepository.deleteAllInBatch();
List<User> users = new ArrayList<>();
users.add(user);
//删除集合,一条一条删除
userRepository.delete(users);
//删除集合,一条sql,拼接or语句 如 id=1 or id=2
userRepository.deleteInBatch(users);

除了默认的api。我们还可以使用上面提到的jpql,这样我们就可以在dao层做到类似mybatis基于注解开发那样的实现了

    //更新(增删改)语句需要@Modifying注解配合,其他规则一致
    @Query(value = "update JpaTest set info = ?0 where id = ?1")
    @Modifying
    int updateJpaTest(String info,int id);

刚打完球,比较累,就不说接下来的关系映射了,也就是几个注解的事情,最后一句,国足加油!

github,jpa模块

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值