上篇文章《SpringBoot讲解二:使用Spring Data JPA替换掉Mybatis框架》讲解了在项目中如何使用Spring Data JPA,本篇文章详细讲解Spring Data JPA的用法。
首先yml中应如下配置:
jpa:
properties:
hibernate:
hbm2ddl:
auto: update
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
format_sql: true
enable_lazy_load_no_trans: true
show-sql: true
关联关系
ManyToOne
OneToOne和ManyToOne是一回事:
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)//会在mysql中建立唯一索引
private String name;
@Column(nullable = false)
private String sex;
@Column(nullable = false)
private int age;
@JoinColumn(name="d_id")
@ManyToOne(cascade = CascadeType.REFRESH)
private Department dep;
}
以上代码会在数据库中生成一个employee表,自动生成列d_id,并且加上了外键约束。
如果不想要外键约束的话,可以这样:
@JoinColumn(name = "d_id", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT))
Cascade属性
注意的是,Cascade配置成Persist,表示是保存emp,同时会保存dep。但是实际项目中,我们用的很少,因为保存emp的时候,实际就是从数据库中查出的dep,所以不会用到这种。
如果用MERGE,这个是根据当前的dep更新一下数据库中的记录,这个时候若dep对象数据和数据库的不对称,也会更新到数据库,其实最好还是设置成REFRESH,这样是符合我们开发习惯的。
OneToMany
@Entity
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column
private String name;
// @JoinColumn(name = "d_id")
@OneToMany(cascade = CascadeType.REFRESH, mappedBy = "dep",fetch=FetchType.LAZY)
private List<Employee> emps;
mappedBy
以上需要注意的是mappedBy属性和JoinColumn不能共存,表示的是谁维护关联关系
inverse和mappedBy作用一样,inverse是用于xml配置,而mappedBy则是用于注解中。
其作用是,将一对多交给多的一方维护关系,如果交给一的一方维护关系的话,一先insert自己,多再insert自己,然后一再去update多。交给多的一方则,一线insert自己,多再insert自己的时候顺便把d-id给插入值。但交给多的一方维护,需要在对象上在多的一方再加上一的一方的对象,总之要提高性能,就要多写代码,实际项目中可以根据实际情况使用。
fetch
默认在多对一情况下,值是Eager即时加载,在一对多和多对多情况下,则默认是Lazy,懒加载。在实际项目中,一般根据默认设置即可。如果是自己写JPQL语句,在语句中写fetch的话,则都为即时加载,其都规训局部设置高于全局设置这种思想。
ManyToMany
如在景点的rbac的权限设计下,User和Role是多对多的关系。
以上为设置中间表,取消外键约束的设置。
自动生成createTime和UpdateTime
字段上设置:
类名上需要加入:
启动类上需要加入:
分页查询
Spring Data JPA提供了PageRequest类进行分页处理
@Override
public Page<SysUser> search(Integer page, Integer size) {
Sort sort = Sort.by(Sort.Direction.DESC, "id");
//spring data jpa 分页,page首页默认为0
PageRequest pageRequest = PageRequest.of(page - 1, size, sort);
Page<SysUser> all = sysUserRepository.findAll(pageRequest);
return all;
}
动态条件查询
Spring Data JPA提供了Specification 接口进行动态条件查找,这里主要是使用了匿名内部类的形式
public Page<SysUser> search(Integer page, Integer size, SysUser sysUser) {
Sort sort = Sort.by(Sort.Direction.ASC, "id");
PageRequest pageRequest = PageRequest.of(page - 1, size, sort);
Specification specification = new Specification() {
@Override
public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
List<Predicate> predicates = new ArrayList<>();
if (!StringUtils.isEmpty(sysUser.getAge())) {
Predicate predicate = criteriaBuilder.equal(root.get("age").as(String.class), sysUser.getAge());
predicates.add(predicate);
}
return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
}
};
Page<SysUser> all = sysUserRepository.findAll(specification, pageRequest);
return all;
}
掌握以上Spring Data JPA的用法,便几乎可以应付项目开发中的所有工作。