Spring Boot整合Spring Data JPA

1.简介
2.整合Spring Data JPA
3.JPA提供的核心接口
4.关联映射

1.简介

Spring Data:

Spring提供了一个操作数据的框架,而Spring Data JPA只是Spring Data框架下一个基于JPA标准操作数据的模块

Spring Data JPA:

基于JPA标准对数据进行操作。简化操作持久层代码,只需要编写接口。

2.整合Spring Data JPA

  1. 搭建整合环境
    修改pom文件,添加坐标

        
            org.springframework.boot
            spring-boot-starter-data-jpa
        

        
        
            org.springframework.boot
            spring-boot-starter-test
        

        
            mysql
            mysql-connector-java
        
  1. 配置application.properties
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/ssm
spring.datasource.username=root
spring.datasource.password=951105

#spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

spring.jpa.hibernate.ddl-auto=update
# 显示sql语句
spring.jpa.show-sql=true
  1. 添加实体类
    3.1 添加注解@Entity,表示当前类是实体类。
    3.2 添加注解@Table(name = "t_users"),指定数据库中的表名
    3.3 添加注解@Id, 表明当前属性为主键
          设置主键生成策略 @GeneratedValue(strategy = GenerationType.IDENTITY)
    3.4 @Column(name = "id") 表示属性与数据库表中的哪一列的映射关系
@Entity
// 设置数据库中的表名
@Table(name = "t_users")
public class Users {
    // 设置主键
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    // 对应数据库中表格的哪一行
    @Column(name = "id")
    private Integer id;
    @Column(name = "name")
    private String name;
    @Column(name = "age")
    private Integer age;
    @Column(name = "address")
    private String address;
  1. 编写Dao接口
public interface UsersRepository extends JpaRepository {
}
  1. 编写启动类
  2. 编写测试代码
    通过JPA生成表,并添加数据
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = App.class)
public class UsersRepositoryTest {

    @Autowired
    private UsersRepository usersRepository;

    @Test
    public void testSave(){
        Users users = new Users();
        users.setName("张三");
        users.setAge(18);
        users.setAddress("china");
        this.usersRepository.save(users);
    }
}

3.Spring Data JPA提供的核心接口

  1. Repository接口
    1.1 方法名称命名查询方式
    1.2 基于@Query注解查询与更新
  2. CrudRepository接口
  3. PagingAndSortingRepository接口
  4. JpaRepository接口
  5. JPASpecificationExecutor接口


1. Repository接口

1.1 方法名称命名查询方式
方法的名称必须要遵循驼峰式命名规则。findBy(关键字)+属性名称(首字母要大写)
+查询条件(首字母大写)

编写Dao接口

public interface UsersRepositoryByName extends Repository {

    //方法的名称必须要遵循驼峰式命名规则。findBy(关键字)+属性名称(首字母要大写)+查询条件(首字母大写)
    List findByName(String name);
    
    List findByNameAndAge(String name,Integer age);
    
    List findByNameLike(String name);
}

编写测试类

    @Test
    public void testFindByName(){
        List list = this.usersRepositoryByName.findByName("张三");
        for(Users users :list){
            System.out.println(users);
        }
    }

1.2 基于@Query注解查询与更新

  • 查询直接加@Query注解
  • 需要更新数据库中信息还需要添加@Modifying注解
    @Query("from Users where name = ?")
    List queryByNameUseHQL(String name);
    
    @Query(value="select * from t_users where name = ?",nativeQuery=true)
    List queryByNameUseSQL(String name);
    
    @Query("update Users set name  = ? where id  = ?")
    @Modifying //需要执行一个更新操作
    void updateUsersNameById(String name,Integer id);

2. CrudRepository接口

主要完成一些增删改查的操作。继承了Repository接口,能使用其所有操作

  • save
    save方法,已经加了事务的注解。由源码可以看出,save方法即是插入,也是更新。(当数据库中有该对象时,就是更新,没有时,就是插入)


    save

3. PagingAndSortingRepository接口

实现排序和分页的功能,只能对全部数据进行分页与排序。

  1. 分页
        //Pageable:封装了分页的参数,当前页,每页显示的条数。注意:他的当前页是从0开始。
        //PageRequest(page,size) page:当前页。size:每页显示的条数
        Pageable pageable = new PageRequest(1, 2);
        Page page = this.usersRepositoryPagingAndSorting.findAll(pageable);
        System.out.println("总条数:"+page.getTotalElements());
        System.out.println("总页数"+page.getTotalPages());
        List list = page.getContent();
        for (Users users : list) {
            System.out.println(users);
        }
  1. 排序
    2.1 定义排序规则order
    Order(Direction.DESC,"id"); 第一个参数为: 设置降序,第二个参数为:选择那个字段进行排序操作
    2.2 使用sort对象封装排序规则
        //Order 定义排序规则
        Order order = new Order(Direction.DESC,"id");
        //Sort对象封装了排序规则
        Sort sort = new Sort(order);
        List list = (List)this.usersRepositoryPagingAndSorting.findAll(sort);
        for (Users users : list) {
            System.out.println(users);
        }
  1. 排序加分页
    将封装了排序规则的sort对象放在PageRequest方法中
        Sort sort = new Sort(new Order(Direction.DESC, "id"));
        
        Pageable pageable = new PageRequest(1, 2, sort);
                
        Page page = this.usersRepositoryPagingAndSorting.findAll(pageable);
        System.out.println("总条数:"+page.getTotalElements());
        System.out.println("总页数"+page.getTotalPages());
        List list = page.getContent();
        for (Users users : list) {
            System.out.println(users);
        }

4. JpaRepository接口

该接口继承了PagingAndSortingRepository接口。对父接口中的方法的返回值进行了适配。

List list = (List)this.usersRepositoryPagingAndSorting.findAll(sort);

PagingAndSortingRepository

这里的findAll方法返回的是一个可迭代类型,需要强转成List。



List list = this.usersJpaRepository.findAll();
JpaRepository

在JpaRepository中,会对方法的返回值进行适配,直接返回List类型的,不需要强转。

5. JPASpecificationExecutor接口

该接口主要是提供了多条件查询的支持,并且可以在查询中添加分页与排序

  1. 单条件
        /**
         * Specification:用于封装查询条件
         */
        Specification spec = new Specification() {
            
            //Predicate:封装了 单个的查询条件
            /**
             * Root root:查询对象的属性的封装。
             * CriteriaQuery query:封装了我们要执行的查询中的各个部分的信息,select  from order by
             * CriteriaBuilder cb:查询条件的构造器。定义不同的查询条件
             */
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
                // where name = '张三三'
                /**
                 * 参数一:查询的条件属性
                 * 参数二:条件的值
                 */
                Predicate pre = cb.equal(root.get("name"), "张三三");
                return pre;
            }
        };
        List list = this.usersRepositorySpecification.findAll(spec);
        for (Users users : list) {
            System.out.println(users);
        }

Specification:用于封装查询条件

  1. 多条件
    2.1 多条件写法一
    2.2 多条件写法二
多条件写法一:
        /**
         * Specification:用于封装查询条件
         */
        Specification spec = new Specification() {
            
            //Predicate:封装了 单个的查询条件
            /**
             * Root root:查询对象的属性的封装。
             * CriteriaQuery query:封装了我们要执行的查询中的各个部分的信息,select  from order by
             * CriteriaBuilder cb:查询条件的构造器。定义不同的查询条件
             */
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
                // where name = '张三三' and age = 20
                List list = new ArrayList<>();
                list.add(cb.equal(root.get("name"),"张三三"));
                list.add(cb.equal(root.get("age"),20));
                Predicate[] arr = new Predicate[list.size()];
                return cb.and(list.toArray(arr));
            }
        };
        List list = this.usersRepositorySpecification.findAll(spec);
        for (Users users : list) {
            System.out.println(users);
        }

多条件写法二:
Specification spec = new Specification() {
            
            //Predicate:封装了 单个的查询条件
            /**
             * Root root:查询对象的属性的封装。
             * CriteriaQuery query:封装了我们要执行的查询中的各个部分的信息,select  from order by
             * CriteriaBuilder cb:查询条件的构造器。定义不同的查询条件
             */
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
                // where name = '张三三' and age = 20
                /*List list = new ArrayList<>();
                list.add(cb.equal(root.get("name"),"张三三"));
                list.add(cb.equal(root.get("age"),20));
                Predicate[] arr = new Predicate[list.size()];*/
                //(name = '张三' and age = 20) or id = 2
                return cb.or(cb.and(cb.equal(root.get("name"),"张三三"),cb.equal(root.get("age"),20)),cb.equal(root.get("id"), 2));
            }
        };
        
        Sort sort = new Sort(new Order(Direction.DESC,"id"));
        List list = this.usersRepositorySpecification.findAll(spec,sort);
        for (Users users : list) {
            System.out.println(users);
        }
  1. 多条件加分页
    在findAll方法中,加上sort参数,spec参数照旧
        Specification spec = new Specification() {
            
            
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
                
                
                return cb.or(cb.and(cb.equal(root.get("name"),"张三三"),cb.equal(root.get("age"),20)),cb.equal(root.get("id"), 2));
            }
        };
        
        Sort sort = new Sort(new Order(Direction.DESC,"id"));
        List list = this.usersRepositorySpecification.findAll(spec,sort);
        for (Users users : list) {
            System.out.println(users);
        }



4.关联映射

1. 一对多关联映射

多的一方:Users

  • 添加外键
  • 级联操作(新建用户时,可能会新建一个角色,需要添加级联操作,通过添加新角色信息到数据库中)

单的一方:Roles

  • @OneToMany(mappedBy = "roles") 根据roles相同的属性,来添加users到Set集合中
    // 添加级联操作。 保存新用户,新用户中可能有新角色,级联保存新角色信息
    @ManyToOne(cascade = CascadeType.PERSIST)
    // 维护外键
    @JoinColumn(name = "roles_id")
    private Roles roles;
    @OneToMany(mappedBy = "roles")
    private Set users = new HashSet<>();

保存操作与查询操作

    @Test
    public void testSave(){
        // 创建一个用户
        Users users = new Users();
        users.setAddress("天津");
        users.setAge(32);
        users.setName("小刚");
        // 创建一个角色
        Roles roles = new Roles();
        roles.setRolename("管理员");
        // 关联
        roles.getUsers().add(users);
        users.setRoles(roles);
        // 保存
        this.usersRepository.save(users);
    }

    @Test
    public void testFind(){
        Users findOne = this.usersRepository.findById(5).orElse(null);
        System.out.println(findOne);
        Roles roles = findOne.getRoles();
        System.out.println(roles.getRolename());
    }

2. 多对多关联映射

    @ManyToMany(cascade=CascadeType.PERSIST,fetch=FetchType.EAGER)
    //@JoinTable:映射中间表
    //joinColumns:当前表中的主键所关联的中间表中的外键字段
    @JoinTable(name="t_roles_menus",joinColumns=@JoinColumn(name="role_id"),inverseJoinColumns=@JoinColumn(name="menu_id"))
    private Set menus = new HashSet<>();
    @ManyToMany(mappedBy="menus")
    private Set roles = new HashSet<>();

你可能感兴趣的:(Spring Boot整合Spring Data JPA)