springdata-jpa(一)单表操作

  • Post author:
  • Post category:其他




springdata-jpa (一)单表操作



1.简介

Spring Data 项目的目的是为了简化构建基于 Spring 框架应用的数据访问,包括关系型数据库库、非关

系型数据库、Map-Reduce 框架、云数据服务等。Spring Data JPA是Spring Data下面的一个子项目,其提供了对JPA的操作支持。

在这里插入图片描述

在这里插入图片描述

JPA(Java Persistence API)是当年的Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据。它的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate,TopLink,JDO等 ORM框架各自为营的局面。值得注意的是,JPA是在现有Hibernate,TopLink,JDO等ORM框架的基础上发展而来的。JPA在JAVA EE 5的时候也加入了其规范之中。

注意,JPA是一套规范,而不是产品。Hibernate是一个ORM框架,它实现了JPA的规范。

Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增删改查等在内的常用功能,使用 Spring Data JPA 可以极大提高开发效率!

Spring Data JPA让我们解脱了DAO层的操作,基本上所有CRUD都可以依赖于它来实现。



2、使用

springboot中使用Spring Data JPA,需要引入其对应的starter,maven会自动引入JPA及其相应的实现,它默认采用的是hibernate的实现。pom.xml中导入springdata-jpa其对应的starter

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

application.properties文件

server.port=9999
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.65.129:3316/work?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.password=123456
spring.datasource.username=root

#如果需要,可以进行自动建表
spring.jpa.hibernate.ddl-auto=update

#如果需要,可以执行指定的sql文件进行建表
#spring.datasource.schema=sql/test.sql

#如果需要,可以显示执行的sql语句
spring.jpa.show-sql=true

#如果需要,可以格式化sql语句
spring.jpa.properties.hibernate.format_sql=true

springboot中对spring Data JPA的配置参数:


官方地址

在这里插入图片描述

Spring Data JPA中采用泛型接口的形式,预先定义好了一些基本的CURD的方法。泛型中需要提供操作的实体类型以及对应的主键类型。

注意,我们无需实现这些方法,Spring Data JPA框架中已经实现了,我们只需在依赖注入后,直接使用即可。

dao层接口UserRepository

package com.hzx.springdatajpa.repository;

import com.hzx.springdatajpa.bean.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User,Long> {

}

实体类User

@Entity
@Table(name = "t_user")
public class User implements Serializable {
//    oracle数据库主键的生成策略(sequence)
//    @Id
//    @GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "myGenerator")
//    @SequenceGenerator(name = "myGenerator",sequenceName = "my_seq")
    
    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false,unique = true)
    private String name;

    @Column(nullable = false)
    private Integer age;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false)
    private Gender gender;

    public User(Long id, String name, Integer age, Gender gender) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Gender getGender() {
        return gender;
    }

    public void setGender(Gender gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender=" + gender +
                '}';
    }
}

@Entity 表示当前类是JPA中的一个实体类

@Table(name=“t_user”)表示当前实体类对应数据库中的表t_user

@Id表示当前属性对应t_user表中的主键列

@GeneratedValue表示该属性对应的t_user表中列值是自动增长的

@Column(nullable = false,unique = true)表示当前属性对应t_user表中的列值是非空唯一的

@Enumerated(EnumType.STRING)表示当前属性对应枚举类型的String形式,而不是原始编号

注意,如果是Oracle数据库的话,可以使用序列来产生主键列的值,代码在注释部分

测试类:

@SpringBootTest
class SpringDataJpaApplicationTests {

    @Autowired
    public UserRepository userRepository;

    @Test
    void contextLoads() {
        User zhangsan = new User("zhangsan", 20, Gender.MAN);
        User lii = new User("lii", 21, Gender.MAN);
        User wangwu = new User("wangwu", 22, Gender.MAN);
        userRepository.save(zhangsan);
        userRepository.save(lii);
        userRepository.save(wangwu);
        System.out.println("-----------------------------");

        List<User> all = userRepository.findAll();
        all.forEach(System.out::println);
        System.out.println("------------------------------");

        User user = userRepository.findById(12L).orElse(null);
        System.out.println("更新前:"+user);
        user.setName("hzx");
        userRepository.save(user);
        System.out.println("更新后:"+user);
        System.out.println("-------------------------------");
        userRepository.deleteAllInBatch();

    }
    
}

在运行的时候JPA会自动建表,因为在application.properties中设置了如下属性

spring.jpa.hibernate.ddl-auto=update

dao层接口中,只继承了JPARepository接口,并没有定义其他方法,但是基本的操作依然可以使用。



3、查询

Spring Data JPA中提供了强大的查询功能,我们只需要在dao层接口中按规则,定出对应的查询方法,那么Spring Data JPA会根据我们所定义的 方法名 ,自动生成对应的sql语句,例如:

public interface UserRepository extends JpaRepository<User,Long> {
    User findByName(String name);

    List<User> findByAge(int age);

    List<User> findByNameOrAge(String name,int age);

    List<User> findByNameLike(String name);

    User findByNameIgnoreCase(String name);

    List<User> findByAgeOrderByNameDesc(int age);

    //first和top的效果是一样的,默认取第一条数据
    User findFirstByOrderByAgeAsc();

    User findFirstByOrderByAgeDesc();

    User findTopByOrderByAgeAsc();

    User findTopByOrderByAgeDesc();

    //first和top后面都可以跟数字,表示取查询数据的前N条数据
    List<User> findFirst2ByGender(Gender gender);
}

当在测试类中调用我们自己在接口中定义的findByName方法的时候,会自动生成对应的sql语句:

@Test
public void test_findByName(){
    User hzx = userRepository.findByName("hzx");
    System.out.println(hzx);
}

控制台中输出的sql为:

在这里插入图片描述

当在测试类中调用我们自己在接口中定义的 findFirst2ByGender 方法的时候,会自动生成对应的sql语句:

@Test
public void test_findFirst2ByGender(){
    List<User> first2ByGender = userRepository.findFirst2ByGender(Gender.MAN);
    first2ByGender.forEach(System.out::println);
}

控制台中输出的sql为:

在这里插入图片描述

可以输出sql语句,因为在application.properties中配置了对应的属性:

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

在方法中所支持的关键字有很多,

官网说明

如下:


Keyword

方法名中支持的关键字


Sample

方法名示例


JPQL snippet

JPA生成的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

findByFirstname

,

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

只要按照以上规则在接口中定义方法,那么Spring Data JPA会自动生成对应的 条件查询 语句



4、排序

Spring Data JPA中可以使用 Sort 对查询的结果进行排序,让 Sort 作为查询方法的参数即可。父接口中已经有定好的方法的参数含有 Sort ,例如 JpaRepository 中的 List findAll(Sort sort);也可以自己在接口中自定义方法的参数中添加 Sort 参数:

public interface UserRepository extends JpaRepository<User,Long> {
    
    List<User> findByGender(Gender gender,Sort sort);
    
    List<User> findFirst20ByGender(Gender gender, Sort sort);
}
@Test
public void test_sort1(){
    List<User> age = userRepository.findAll(Sort.by(Sort.Direction.DESC, "age"));
    age.forEach(System.out::println);
}

生成的sql语句为:

在这里插入图片描述

@Test
public void test_sort2(){
    List<User> age = userRepository.findByGender(Gender.MAN, Sort.by(Sort.Direction.ASC, "age"));
    age.forEach(System.out::println);
}

生成的sql语句为:

在这里插入图片描述

@Test
public void test_sort3(){
    List<User> age = userRepository.findFirst20ByGender(Gender.MAN, Sort.by(Sort.Direction.ASC, "age"));
    age.forEach(System.out::println);
}

生成的sql语句为:

在这里插入图片描述

Sort中的by方法声明为:可以接受多个排序的参数

public static Sort by(Sort.Direction direction, String... properties)



5、分页

Spring Data JPA中分页功能和排序的使用方式类似,只需要在查询方法的参数列表中添加一个Pageable 类型的参数即可。

父接口中已经有定好的方法的参数含有 Pageable ,例如 PagingAndSortingRepository 中的

Page findAll(Pageable pageable);

也可以自己在接口中自定义方法的参数中添加 Pageable 参数:

public interface UserRepository extends JpaRepository<User,Long> {

    Page<User> findByGender(Gender gender, Pageable pageable);

    Page<User> findFirst25ByGender(Gender gender, Pageable pageable);

    List<User> findTop25ByGender(Gender gender, Pageable pageable);

}

方法的返回类型是可以是Page类型的,也可以是List集合类型,只是Page类型的返回值可以提供更多的分页相关信息。

@Test
public void test_pageable1(){
    int page=0;
    int size=2;
    PageRequest pageable = PageRequest.of(page, size);
    Page<User> pageObj = userRepository.findAll(pageable);
    System.out.println("总页数:  "+pageObj.getTotalPages());
    System.out.println("总数据量:  "+pageObj.getTotalElements());
    System.out.println("当前的页码:  "+pageObj.getNumber());
    System.out.println("每页条数:  "+pageObj.getSize());
    System.out.println("当前页实际条数:  "+pageObj.getNumberOfElements());
    System.out.println("当前页内容:  "+pageObj.getContent());
    System.out.println("分页查询的排序规则为:  "+pageObj.getSort());
    System.out.println("当前是否为第一页:  "+pageObj.isFirst());
    System.out.println("当前是否为最后一页:  "+pageObj.isLast());
    System.out.println("当前是否有上一页:  "+pageObj.hasPrevious());
    System.out.println("当前是否有下一页:  "+pageObj.hasNext());
    System.out.println("返回上一页Pageable对象为:  "+pageObj.previousPageable());
    System.out.println("返回下一页Pageable对象为:  "+pageObj.nextPageable());
}

生成的sql语句为:

在这里插入图片描述

运行结果为:

在这里插入图片描述



6、注解

Spring Data JPA中可以在接口中自定义方法上面使用 @Query 注解,在该注解中可以使用JPQL或SQL来指定此方法被调用的时候需要执行的sql语言是什么。

JPQL(JavaPersistence Query Language)是一种面向对象的查询语言,它在ORM框架中最终会翻译成为sql进行执行。在hibernate框架中,这种语句叫做HQL(Hibernate Query Language)。

JPQL是面向对象的查询语言,在查询语句中,出现的不是表的名字、字段的名字,而是类的名字和类中属性的名字,因为在ORM框架中,类和表,属性和字段都做好了映射关系,所以JPQL最后是可以根据映射关系转换sql语句的。

JPQL的特点:

  • 语句中不能出现表名,列名,只能出现java的类名,属性名,并且区分大小写

  • 语句中出现的关键字和sql语句中的是一样的意思,不区分大小写

  • 语句中不能写select * 而是要写select 类的别名,或者写select 具体的属性名

@Query("select u from User where u.name = ?1")
User findByUsername(String name);

该语句中的?1代表的是第一个参数,?2代表第二个参数

也可以配合@Param注解使用命名参数的方式:

@Query("select u from User u where u.name = :name or u.age = :age")
User findByNameOrAge(@Param("name") String name,
                     @Param("age") int age);

@Query 注解还可以支持更新和删除的语句,但是需要结合 @Modifying 注解,以及事务管理的注解@Transactional

@Transactional
@Modifying
@Query("update User u set u.name = ?1 where u.id = ?2")
int updateNameByUserId(String name,Long id);

@Transactional
@Modifying
@Query("delete from User u where u.id = ?1")
void deleteByUserId(Long id);

以上代码在https://gitee.com/huangzhixiong2021/spring-data-jpa.git 中,有不足或者错误的地方欢迎指正。



版权声明:本文为weixin_43521932原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。