JPA(Java Persistence API)Java持久化API。Spring Data JPA是spring提供的一套简化JPA开发的框架,底层还是使用了hibernate的JPA技术实现。
持久化工具都有一个对象来操作数据库,原生的Hibernate中叫做Session,JPA中叫做EntityManager,MyBatis中叫做SqlSession。
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependencies>
springboot集成jpa
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/zhu
username: root
password: root
jpa:
hibernate:
# create 每次启动重新创建表
# update 更新,原数据不会清空
# validate 校验,字段不同会报错
# none 禁用ddl
ddl-auto: update
show-sql: true
The central interface in the Spring Data repository abstraction is Repository.
CrudRepository接口提供复杂的CRUD功能
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
// 保存
<S extends T> S save(S entity);
// 返回给定ID标识的实体
Optional<T> findById(ID primaryKey);
// 给定ID实体是否存在
boolean existsById(ID primaryKey);
// 返回所有实体
Iterable<T> findAll();
// 返回实体数量
long count();
// 删除指定ID实体
void deleteById(ID primaryKey);
// 删除指定实体
void delete(T entity);
}
PagingAndSortingRepository简化对实体的分页访问
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
}
public interface PeopleRepository extends PagingAndSortingRepository<People, Integer> {
}
// 对User的分页查询
Page<User> users = peopleRepository.findAll(PageRequest.of(pageNum, pageSize, Sort.by("id").ascending()));
根据方法名称创建查询
public interface PeopleRepository extends PagingAndSortingRepository<People, Integer> {
// 根据名称和国家查
People findByNameAndCountry(String name, String country);
// 根据名称或国家查
People findByNameOrCountry(String name, String country);
// between
List<People> findByAgeBetween(Integer age1, Integer age2);
// lessThan小于/lessThanEqual小于等于/greaterThan大于/greaterThanEqual大于等于
List<People> findByAgeIsLessThan(Integer age);
// isNull/isNotNull/isLike/isNotLike/isStartingWith/isEndingWith/Containing/not/in......
List<People> findByNameIsNull(..);
// first5/top5 前5条数据
List<People> findFirst5ByName(String name);
// 根据名字查询结果按年龄升序,并提供排序和分页功能
List<Person> findByNameOrderByAgeAsc(String name, int age, Sort sort, PageRequest pageRequest);
//Spring Data JPA 支持@Query来定义查询方法,使用方法是将@Query写在接口的方法上面
@Query(select p from Person p where p.name = ?1 and p.country = ?2")
Person selectByNameAndCountry(String name, String country);
@Query(select p from Person p where p.name = :name and p.country = :country")
Person selectByNameAndCountry(@Param("name")String name, @Param("country")String country);
// 更新
@Modify
@Transcational
@Query("update Person p set p.name = ?1 where p.id = ?2 ")
int setName(String name, Integer id);
// hql模糊查询
@Query("select u from user u where u.name like concat('%', ?1, '%')")
User findByName(String name);
// 查询指定字段, 得在User中存在id和name得构造函数,否则启动报错:Unable to locate appropriate constructor on class
@Query("select new User(a.id, a.name) from User as a where a.name = ?1 ")
Page<User> queryPartColumns(String name, Pageable pageable);
// Spring Data Jpa目前不支持对原生查询进行动态排序,但可以通过自己指定计数查询countQuery来使用原生查询进行分页、排序
@Query(value = "select * from User u where u.namelike %?1%",
countQuery = "select count(1) from User u where u.name= %?1%",
nativeQuery = true)
Page<User> queryByUsernameLike(String username, Pageable pageable);
}
// 调用
peopleRepository.findByNameOrderByAge("Tom",20, Sort.by("id").ascending(),
PageRequest.of(0,5));
动态条件分页查询
// 分页条件查询 Page<S> findAll(Example<S> example, Pageable pageable);
User user = new User();
user.setName("tom");
ExampleMatcher matcher = ExampleMatcher.matching()
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINTING) // 改变默认字符串匹配方式:模糊查询
.withIgnoreCase(true)
.withMatcher("country", ExampleMatcher.GenericPropertyMatchers.startsWith()) //地区采用“开始匹配”的方式查询
.withIgnorePaths("age") // 忽略属性age;
Example<User> example = Example.of(user);
Page<User> page = userRepository.findAll(example, PageRequest.of(0, 3));
// 分页条件查询 Page<T> findAll(Specification<T> spe, Pageable pageable);
Page<User> page = userRepository.findAll((Specification<User>) (root, criteriaQuery, criteriaBuilder) -> {
List<Predicate> list = new ArrayList<>();
if (StringUtils.isNotBlank(name)) {
list.add(criteriaBuilder.like(root.get("name").as(String.class), '%' + name + '%'));
}
if (null != age) {
list.add(criteriaBuilder.equal(root.get("age").as(Integer.class), age));
}
return criteriaQuery.where(list.toArray(new Predicate[list.size()])).getRestriction();
}, PageRequest.of(pageNo, pageSize));
// 还可使用EntityManager
StringBuilder sqlStr = new StringBuilder("select new User(a.name,a.age) from User a where 1=1 ");
StringBuilder countStr = new StringBuilder("select count(1) from tbl_user a where 1=1 ");
if (StringUtils.isNotBlank(name)) {
sqlStr.append(" and a.name = :name);
countStr.append(" and a.user_name = :name);
}
// createQuery使用HQL语句实现查询,以hibernate生成的Bean为对象装入list返回
/**
* createNativeQuery使用SQL语句实现查询
* List<User> = query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(User.class)).getResultList();
*/
Query query = entityManager.createQuery(sqlStr.toString(), User.class);
Query countQuery = entityManager.createNativeQuery(sqlStr.toString());
if (StringUtils.isNotBlank(name)) {
query.setParameter("name", name);
countQuery.setParameter("name", name);
}
long total = (long)countQuery.getSingleResult();
query.setFirstResult(pageNo * pageSize).setMaxResults(pageSize);
Page<user> page = new PageImpl<>(query.getResultList(), PageRequest.of(pageNo, pageSize), total);
多表查询
// 实体类 多对多
@ManyToMany(targetEntity = Role.class, cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
@JoinTable(name = "tb_user_role", joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id")})
private Set<Role> roles;
// 调用
Optional<User> optional = userRepository.findById("1");
Set<Role> roles = optional.get().getRoles();
System.out.println(optional.get());
// spring Boot整合JPA后Hibernate的Session就交付给Spring去管理。每次数据库操作后,会关闭Session,当我们想要用懒加载方式去获得数据的时候,原来的Session已经关闭,不能获取数据
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
// 一对多/多对一 一个部门包含多个员工
// Department 部门表
@OneToMany(mappedBy = "department", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Employee> employees;
// Emplouee 员工表
@ManyToOne(targetEntity = Department.class, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "dept_id")
private Department department;
Spring Data Jpa支持审计功能: @CreatedBy,@LastModifiedBy,@CreatedDate,@LastModifiedDate 4个注解
启动类上添加@EnableJpaAuditing注解启用Jpa的审计功能
实体类加注解@EntityListeners(AuditingEntityListener.class)