Spring Data JPA(3)

1 Specifications动态查询

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

1.1 使用Specifications完成条件查询

Specification构造自定义查询条件

  1. 实现Specification接口(提供泛型:查询的对象类型)
  2. 实现toPredicate方法(构造查询条件)
  3. 需要借助方法参数中的两个参数
  • root:获取需要查询的对象属性
  • CriteriaBuilder:构造查询条件,内部封装了很多的查询条件(模糊匹配,精准匹配)
Specification specification = new Specification() {
    @Override
    public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
        //获取比较的属性
        Path id = root.get("id");
        //构造查询条件
        //第一个参数:需要比较的属性(path对象)
        //第二个参数:当前需要比较的取值
        Predicate predicate = criteriaBuilder.equal(id, 67);
        return predicate;
    }
};
User user = userDao.findOne(specification);

  1. 多条件查询时,可以用criteriaBuilder.and或or进行连接
  2. 比较查询(如like、lt)时,需要比较的属性需要使用对应的.as属性

1.2 使用Specifications完成排序

Sort sort = new Sort(Sort.Direction.DESC, "id");
userDao.findAll(specification, sort);

1.3 使用Specifications完成分页查询

分页查询:

  • Specification: 查询条件
  • Pageable:分页参数

返回值:

  • Page:springDataJpa为我们封装好的pageBean对象,数据列表、总条数、总页数
        //第一个参数:当前查询的页数(从0开始)
        //第二个参数:每页查询数量
        Pageable pageable = new PageRequest(0,3);
        Page userPage = userDao.findAll(specification, pageable);
        System.out.println(userPage.getTotalElements());//总条数
        System.out.println(userPage.getTotalPages());//总页数
        List users = userPage.getContent();//数据列表

1.4 方法对应关系

比较属性时的方法名称与sql对应关系

方法名称 Sql对应关系
equal filed = value
gt(greaterThan ) filed > value
lt(lessThan ) filed < value
ge(greaterThanOrEqualTo ) filed >= value
le( lessThanOrEqualTo) filed <= value
notEqual filed != value
like filed like value
notLike filed not like value

2 JPA中的一对多

2.1 在实体类一的一方维护一对多的关系

  1. 使用@OneToMany注解声明一对多的关系,配置属性
  • targetEntity:多的一方实体的字节码对象
  1. 使用@JoinColumn注解配置外键(中间表),配置属性
  • name:多的一方数据表外键字段名称
  • referencedColumnName:一的一方数据表主键字段名称

在一的一方添加的外键配置,对于一的一方而言,也具备了维护外键的的作用。

通过执行语句发现,其执行过程为:一的一方添加数据 -> 多的一方添加数据 -> 更新多的一方外键字段,这样其实是影响效率

  1. 通过@OneToMany(mappedBy = "user")注解放弃外键维护,将外键维护权交给多的一方
  • mappedBy:对应属性值为多的一方声明的对应一的一方的属性名称
  • fetch:配置关联对象的加载方式(一的一方默认延迟加载,多的一方默认立即加载)
    //@OneToMany(targetEntity = Account.class)
    //@JoinColumn(name="uid", referencedColumnName = "id")
    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private Set accounts = new HashSet<>();

2.2 在实体类多的一方维护一对多的关系

  1. 使用@ManyToOne注解配置多对一的关系,配置属性
  • targetEntity:一的一方实体的字节码对象
  1. 使用@JoinColumn注解配置外键(中间表),配置属性
  • name:多的一方数据表外键字段名称
  • referencedColumnName:一的一方数据表主键字段名称

配置外键的过程,配置到了多的一方,就会在多的一方维护外键

    @ManyToOne(targetEntity = User.class)
    @JoinColumn(name="uid", referencedColumnName = "id")
    private User user;

2.3 测试

        User user = new User();
        user.setUsername("白居易");
        user.setBirthday(new Date());
        user.setSex("男");
        user.setAddress("唐都");

        Account account = new Account();
        account.setName("ww");
        account.setMoney(1000D);

        //user.getAccounts().add(account);
        account.setUser(user);

        userDao.save(user);
        accountDao.save(account);

2.4 级联操作

我们一般在一的一方配置级联,通过注解@OneToMany属性cascade,可以实现对多的一方数据的保存、更新、删除

  • CascadeType.ALL:全部,包括保存、更新、删除
  • CascadeType.MERGE:更新
  • CascadeType.PERSIST:保存
  • CascadeType.REMOVE:删除
        User user = new User();
        user.setUsername("骆宾王");
        user.setBirthday(new Date());
        user.setSex("男");
        user.setAddress("鹅城");

        Account account = new Account();
        account.setName("lbw");
        account.setMoney(1000D);

        user.getAccounts().add(account);
        account.setUser(user);

        userDao.save(user);

3 JPA中的多对多

3.1 实体类注解配置多对多的关系

  1. @ManyToMany声明表关系配置,配置属性:
  • targetEntity:代表对方的实体类字节码
  1. @JoinTable配置中间表(包含两个外键),配置属性:
  • name:中间表的名称
  • joinColumns: 配置当前对象在中间表的外键名称,值为@JoinColumn的数组(name:中间表外键字段名称,referencedColumnName:参照的主表的主键名)
  • inverseJoinColumns:配置对方对象在中间表的外键,值也是@JoinColumn的数组
    @ManyToMany(targetEntity = Role.class, cascade = CascadeType.ALL)
    @JoinTable(name = "user_role",
            joinColumns = {@JoinColumn(name = "uid", referencedColumnName = "id")},
            inverseJoinColumns = {@JoinColumn(name = "rid", referencedColumnName = "id")})
    private Set roles = new HashSet<>();

3.2 另一个实体类注解配置多对多的关系

不能两个实体都进行主键维护,重复向中间表保存数据,会引起中间表的主键冲突,原则是被动的一方放弃,谁被选择就放弃谁,这里的例子是user和role,role表放弃主键维护

//    @ManyToMany(targetEntity = User.class)
//    @JoinTable(name = "user_role",
//            joinColumns = {@JoinColumn(name = "rid", referencedColumnName = "id")},
//            inverseJoinColumns = {@JoinColumn(name = "uid", referencedColumnName = "id")})
    @ManyToMany(mappedBy = "roles")
    private Set users = new HashSet<>();

3.3 测试

        User user = new User();
        user.setUsername("third");
        user.setBirthday(new Date());
        user.setSex("男");
        user.setAddress("third");

        Role role = new Role();
        role.setRoleDesc("第三方");
        role.setRoleName("第三方");

        user.getRoles().add(role);
        //role.getUsers().add(user);

        userDao.save(user);
        roleDao.save(role);

多对多的关系同样可以配置级联操作,但是不建议配置级联删除,user表数据删除时会同时删除role表和中间表的数据

4 对象导航查询

对象图导航检索方式是根据已经加载的对象,导航到他的关联对象。它利用类与类之间的关系来检索对象。一对多默认是延迟加载,多对一默认是立即加载。
如:人员和账户的一对多关系,当查询当人员信息时,可以导航到他的关联对象账户上,延迟加载账户信息;当查询账户时,可以导航到他的关联对象人员上,立即加载人员信息。

        User user = userDao.findOne(46);
        System.out.println(user);
        Set accounts = user.getAccounts();
        for (Account account : accounts) {
            System.out.println(account);
        }

你可能感兴趣的:(Spring Data JPA(3))