SpringBoot+Spring JPA基础使用

  1. Spring JPA集成
  2. 基础查询实例
  3. 复杂查询+分页
  4. 一对多查询及多对多查询

1. Spring JPA集成

1.1 项目配置

如截图所示,需要导入对应的组件,其他的和正常创建SpringBoot一致。


需要加入的组件

1.2 配置文件配置

修改application.yml文件进行如下配置:

spring:
  devtools:
    restart:
      enabled: false
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://[IP地址]:3306/test
    hikari:
      username:[MYSQL 用户名]
      password: [MYSQL 密码]
  jpa:
    hibernate:
      #可选参数 
      #create 启动时删数据库中的表,然后创建,退出时不删除数据表 
      #create-drop 启动时删数据库中的表,然后创建,退出时删除数据表 如果表不存在报错 
      #update 如果启动时表格式不一致则更新表,原有数据保留 
      #validate 项目启动表结构进行校验 如果不一致则报错
      ddl-auto: update
    show-sql: true
    properties:
      hibernate:
        enable_lazy_load_no_trans: true

配置文件配置

2. 基础查询实例

2.1 类创建

2.1.1 实体类创建
@Data
@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;
}

对应的注解意思如下:

  • @Data:lombok注解,生成对应的getter(),setter(),有参构造方法,无参构造方法等。
  • @Entity:表明该类是jpa的一个实体
  • @Table:映射到具体的数据库中的表
  • @Id: 主键
  • @GeneratedValue:生成该值的策略
IDENTITY: 采用数据库ID自增长的方式来自增主键字段,Oracle 不支持这种方式; 
AUTO: JPA自动选择合适的策略,是默认选项; 
SEQUENCE: 通过序列产生主键,通过@SequenceGenerator 注解指定序列名,MySql不支持这种方式 
TABLE: 通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。
  • @Column: 显示建立该表的字段连接关系,默认情况会将驼峰命名转成xx_xxx进行映射。
2.1.2 Dao实体创建
public interface UserDao extends JpaRepository, JpaSpecificationExecutor {

    @Query(value="select * from user where name like ?1",nativeQuery = true)
    public List findSqlByLikeName(String name);

    public User findByName(String name);
}

对应继承的类作用:

  • JpaRepository<实体类型,主键类型>:封装了基础的CURD操作。
  • JpaSpecificationExecutor<操作的实体类类型>:封装了复杂的查询(分页)

对应的操作类型:

  • SQL 语句查询:通过@Query注解,​ nativeQuery : false(使用jpql查询) | true(使用本地查询 :sql查询),第一个参数则为?1,第二个参数则为?2以此类推。
  • 方法命名规则查询
/**
     * 方法名的约定:
     *      findBy : 查询
     *            对象中的属性名(首字母大写) : 查询的条件
     *            CustName
     *            * 默认情况 : 使用 等于的方式查询
     *                  特殊的查询方式
     *
     *  findByCustName   --   根据客户名称查询
     *
     *  再springdataJpa的运行阶段
     *          会根据方法名称进行解析  findBy    from  xxx(实体类)
     *                                      属性名称      where  custName =
     *
     *      1.findBy  + 属性名称 (根据属性名称进行完成匹配的查询=)
     *      2.findBy  + 属性名称 + “查询方式(Like | isnull)”
     *          findByCustNameLike
     *      3.多条件查询
     *          findBy + 属性名 + “查询方式”   + “多条件的连接符(and|or)”  + 属性名 + “查询方式”
     */

2.2 测试

2.2.1 简单测试保存
 @Autowired
 private UserDao userDao;

 @Test
 void simpleSave(){
     User user = new User();
     user.setName("测试2");
     userDao.save(user);
  }
2.2.2 简单测试查询
    @Test
    void sqlSearch(){
        List users = userDao.findSqlByLikeName("测试2");
        System.out.println(users);

    }

    @Test
    void matchSearch(){
        User user = userDao.findByName("测试");
        System.out.println(user);
    }

3. 复杂查询+分页

有时我们在查询某个实体的时候,给定的条件是不固定的,这时就需要动态构建相应的查询语句,在Spring Data JPA中可以通过JpaSpecificationExecutor接口查询。相比JPQL,其优势是类型安全,更加的面向对象。

  • JpaSpecificationExecutor方法列表
1. T findOne(Specification spec); //查询单个对象

2. List findAll(Specification spec); //查询列表

3. 查询全部,分页

    pageable:分页参数

    返回值:分页pageBean(page:是springdatajpa提供的)

    Page findAll(Specification spec, Pageable pageable);

4.查询列表

    Sort:排序参数

    List findAll(Specification spec, Sort sort);

5. long count(Specification spec);//统计查询

我们需要自己实现Specification:

//root:查询的根对象(查询的任何属性都可以从根对象中获取)
//CriteriaQuery:顶层查询对象,自定义查询方式(了解:一般不用)
//CriteriaBuilder:查询的构造器,封装了很多的查询条件
Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb); //封装查询条件

测试

3.1 简单的例子
@Test
    void testSpec(){
        Specification spec = new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
                //1.获取比较的属性
                Path name = root.get("name");
                Path id = root.get("id");
                //2.构造查询条件  :    select * from user where name = '测试1' and id = 1
                /**
                 * 第一个参数:需要比较的属性(path对象)
                 * 第二个参数:当前需要比较的取值
                 */
                Predicate predicate1 = cb.equal(name, "测试2");//进行精准的匹配  (比较的属性,比较的属性的取值)
                Predicate predicate2 = cb.equal(id,1);
                return cb.and(predicate1,predicate2);
            }
        };
        User user = userDao.findOne(spec).get();
        System.out.println(user);


    }
3.2 分页的例子

通过Sort进行排序,PageRequest 进行分页,第一个参数为当前查询的页码(从0开始),第二个参数为每页查询的数量,第三个参数为排序字段。
findAll()支持Specification查询和分页,这样就可以实现复杂类型的查询。

    @Test
    void testPage(){
        Specification spe = null;
        Sort sort = Sort.by(Sort.Direction.DESC,"id");
        PageRequest pageRequest = PageRequest.of(0,2,sort);

        Page users = userDao.findAll(spe,pageRequest);
        System.out.println(users.getTotalPages());
        System.out.println(users.getContent());

    }

4. 一对多查询及多对多查询

假设:用户和班级的关系为:1:N,一个用户可以在不同的班级内。
假设:用户和角色的关系为:N:M,多对多的关系在中间表维护

4.1 类改造及新增

4.1.1 User类改造
@Data
@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @OneToMany(mappedBy = "user",cascade = CascadeType.ALL)
    @org.hibernate.annotations.ForeignKey(name = "none")
    private List classE = new ArrayList<>();

    @ManyToMany(targetEntity = Role.class,cascade = CascadeType.ALL)
    @JoinTable(name = "sys_user_role",
            //joinColumns,当前对象在中间表中的外键
            joinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "id")},
            //inverseJoinColumns,对方对象在中间表的外键
            inverseJoinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "id")}
    )
    private List roles = new ArrayList<>();
}
4.1.2 ClassE类创建
@Entity
@Table(name = "class")
@Getter
@Setter
public class ClassE {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;


    /**
     * 配置联系人到客户的多对一关系
     *     使用注解的形式配置多对一关系
     *      1.配置表关系
     *          @ManyToOne : 配置多对一关系
     *              targetEntity:对方的实体类字节码
     *      2.配置外键(中间表)
     *
     * * 配置外键的过程,配置到了多的一方,就会在多的一方维护外键
     *
     */
    @ManyToOne(targetEntity = User.class,fetch = FetchType.EAGER)
    @JoinColumn(name = "uid",referencedColumnName = "id",foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT))
    private User user;
}
4.1.3 Role类创建
@Entity
@Getter
@Setter
@Table(name = "role")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;
    @Column(name = "name")
    private String name;

    //配置多对多
    @ManyToMany(mappedBy = "roles")  //配置多表关系(对方配置映射关系的属性)
    private List users = new ArrayList<>();
}
4.1.4 Dao分别创建
public interface UserDao extends JpaRepository, JpaSpecificationExecutor {

}

public interface RoleDao extends JpaRepository, JpaSpecificationExecutor {

}

public interface ClassDao extends JpaRepository, JpaSpecificationExecutor {

}

4.2 测试

@Test
    @Transactional
    @Rollback(false)
    void testRoleAdd(){
        User user = new User();
        user.setName("测试人员");
        ClassE classE = new ClassE();
        classE.setName("一班");
        ClassE classE1 = new ClassE();
        classE.setName("二班");
        user.getClassE().add(classE);
        user.getClassE().add(classE1);

        classE.setUser(user);
        classE1.setUser(user);

        Role role = new Role();
        role.setName("角色1");
        Role role1 = new Role();
        role1.setName("角色2");
        user.getRoles().add(role);
        user.getRoles().add(role1);
        userDao.save(user);
        classDao.save(classE);
        classDao.save(classE1);
        roleDao.save(role);
        roleDao.save(role1);
    }

你可能感兴趣的:(SpringBoot+Spring JPA基础使用)