美文网首页
SpringBoot+Spring JPA基础使用

SpringBoot+Spring JPA基础使用

作者: 我知他风雨兼程途径日暮不赏 | 来源:发表于2020-09-17 11:43 被阅读0次
    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<User,Long>, JpaSpecificationExecutor<User> {
    
        @Query(value="select * from user where name like ?1",nativeQuery = true)
        public List<User> 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<User> 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<T> root, CriteriaQuery<?> query, CriteriaBuilder cb); //封装查询条件
    

    测试

    3.1 简单的例子
    @Test
        void testSpec(){
            Specification<User> spec = new Specification<User>() {
                @Override
                public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    //1.获取比较的属性
                    Path<String> name = root.get("name");
                    Path<Long> 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<User> 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> 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<Role> 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<User> users = new ArrayList<>();
    }
    
    4.1.4 Dao分别创建
    public interface UserDao extends JpaRepository<User,Long>, JpaSpecificationExecutor<User> {
    
    }
    
    public interface RoleDao extends JpaRepository<Role,Long>, JpaSpecificationExecutor<Role> {
    
    }
    
    public interface ClassDao extends JpaRepository<ClassE,Long>, JpaSpecificationExecutor<ClassE> {
    
    }
    
    

    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基础使用

          本文链接:https://www.haomeiwen.com/subject/duxlyktx.html