1 Specifications动态查询
有时我们在查询某个实体的时候,给定的条件是不固定的,这时就需要动态构建相应的查询语句,在Spring Data JPA中可以通过JpaSpecificationExecutor接口查询。相比JPQL,其优势是类型安全,更加的面向对象
1.1 使用Specifications完成条件查询
Specification构造自定义查询条件
- 实现Specification接口(提供泛型:查询的对象类型)
- 实现toPredicate方法(构造查询条件)
- 需要借助方法参数中的两个参数
- root:获取需要查询的对象属性
- CriteriaBuilder:构造查询条件,内部封装了很多的查询条件(模糊匹配,精准匹配)
Specification specification = new Specification() {
@Override
public Predicate toPredicate(Root root, CriteriaQuery> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//获取比较的属性
Path
- 多条件查询时,可以用criteriaBuilder.and或or进行连接
- 比较查询(如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 在实体类一的一方维护一对多的关系
- 使用@OneToMany注解声明一对多的关系,配置属性
- targetEntity:多的一方实体的字节码对象
- 使用@JoinColumn注解配置外键(中间表),配置属性
- name:多的一方数据表外键字段名称
- referencedColumnName:一的一方数据表主键字段名称
在一的一方添加的外键配置,对于一的一方而言,也具备了维护外键的的作用。
通过执行语句发现,其执行过程为:一的一方添加数据 -> 多的一方添加数据 -> 更新多的一方外键字段,这样其实是影响效率
- 通过@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 在实体类多的一方维护一对多的关系
- 使用@ManyToOne注解配置多对一的关系,配置属性
- targetEntity:一的一方实体的字节码对象
- 使用@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 实体类注解配置多对多的关系
- @ManyToMany声明表关系配置,配置属性:
- targetEntity:代表对方的实体类字节码
- @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);
}