Spring Data Jpa速通(1)
1 结构关系
1.1 Repositry<>
package org.springframework.data.repository;
import java.io.Serializable;
/**
* Repository 是所有特定 Repository 的顶层接口,仅用于标记。
*/
@NoRepositoryBean
public interface Repository<T, ID extends Serializable> {
}
@NoRedpository
注解表示该接口不会被spring
容器做为Bean实例化
1.2 CurdRepository<T, ID>
package org.springframework.data.repository;
import java.util.Optional;
public interface CrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> S save(S entity); // 保存一个实体,要先判断实体是否存在,再决定插入或更新
Optional<T> findById(ID id); // 根据主键查找
boolean existsById(ID id); // 是否存在
Iterable<T> findAll(); // 查询所有
Iterable<T> findAllById(Iterable<ID> ids); // 根据多个ID查询
long count(); // 总记录数
void deleteById(ID id); // 根据ID删除
void delete(T entity); // 删除实体
void deleteAll(Iterable<? extends T> entities); // 删除多个
void deleteAll(); // 删除全部
}
公共基础的增 删 改 查
1.3 PagingAndSortingRepository<T, ID>
package org.springframework.data.repository;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Page;
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort); // 支持排序
Page<T> findAll(Pageable pageable); // 支持分页
}
1.4 JpaRepository
package org.springframework.data.jpa.repository;
import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.List;
import java.util.Optional;
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
List<T> findAll(); // 返回 List 而非 Iterable
List<T> findAllById(Iterable<ID> ids);
<S extends T> List<S> saveAll(Iterable<S> entities); // 批量保存
void flush(); // 刷新持久化上下文
<S extends T> S saveAndFlush(S entity);
void deleteInBatch(Iterable<T> entities); // 批量删除
void deleteAllInBatch();
T getOne(ID id); // 获取实体的引用(懒加载)
Optional<T> findById(ID id);
}
1.5 SimpleJpaRepository
package org.springframework.data.jpa.repository.support;
import jakarta.persistence.EntityManager;
import jakarta.persistence.LockModeType;
import jakarta.persistence.TypedQuery;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
@Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID> {
private final EntityManager em;
private final JpaEntityInformation<T, ?> entityInformation;
public SimpleJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager em) {
this.entityInformation = entityInformation;
this.em = em;
}
public SimpleJpaRepository(Class<T> domainClass, EntityManager em) {
this.entityInformation = JpaEntityInformationSupport.getEntityInformation(domainClass, em);
this.em = em;
}
// === 查询操作 ===
@Override
public Optional<T> findById(ID id) {
return Optional.ofNullable(em.find(entityInformation.getJavaType(), id));
}
@Override
public List<T> findAll() {
String jpql = "SELECT e FROM " + entityInformation.getEntityName() + " e";
return em.createQuery(jpql, entityInformation.getJavaType()).getResultList();
}
@Override
public Page<T> findAll(Pageable pageable) {
List<T> content = getQuery(pageable).getResultList();
return new PageImpl<>(content, pageable, count());
}
protected TypedQuery<T> getQuery(Pageable pageable) {
String jpql = "SELECT e FROM " + entityInformation.getEntityName() + " e";
TypedQuery<T> query = em.createQuery(jpql, entityInformation.getJavaType());
if (pageable.isPaged()) {
query.setFirstResult((int) pageable.getOffset());
query.setMaxResults(pageable.getPageSize());
}
return query;
}
@Override
public long count() {
String jpql = "SELECT COUNT(e) FROM " + entityInformation.getEntityName() + " e";
return em.createQuery(jpql, Long.class).getSingleResult();
}
// === 保存操作 ===
@Transactional
@Override
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
@Transactional
@Override
public <S extends T> List<S> saveAll(Iterable<S> entities) {
List<S> result = new java.util.ArrayList<>();
for (S entity : entities) {
result.add(save(entity));
}
return result;
}
@Transactional
@Override
public void deleteById(ID id) {
delete(findById(id).orElseThrow(() -> new IllegalArgumentException("Entity not found")));
}
@Transactional
@Override
public void delete(T entity) {
em.remove(em.contains(entity) ? entity : em.merge(entity));
}
@Transactional
@Override
public void deleteAll() {
for (T entity : findAll()) {
delete(entity);
}
}
@Transactional
@Override
public void flush() {
em.flush();
}
@Transactional
@Override
public <S extends T> S saveAndFlush(S entity) {
S result = save(entity);
flush();
return result;
}
@Transactional
@Override
public void deleteInBatch(Iterable<T> entities) {
for (T entity : entities) {
delete(entity);
}
}
// 其他方法略...
}
注意save方法, save方法会判断是否存在来选择调用插入还是更新。
注意delete方法,先查询,查出对象后, 不存在就抛异常, 存在才会删除。
1.6 PagingAndSortingRepository
package org.springframework.data.repository;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Page;
import java.util.List;
/**
* 继承自 CrudRepository,提供分页和排序的功能扩展。
*
* @param <T> 实体类型
* @param <ID> 实体ID类型
*/
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
/**
* 返回所有实体,并按提供的排序条件排序。
*
* @param sort 排序参数
* @return 排好序的实体集合
*/
Iterable<T> findAll(Sort sort);
/**
* 返回分页的实体数据。
*
* @param pageable 分页参数(页码、大小、排序)
* @return 包含分页信息的 Page 对象
*/
Page<T> findAll(Pageable pageable);
}
1.7 QueryByExampleExecutor
package org.springframework.data.repository.query;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import java.util.Optional;
/**
* 通过示例实体进行查询的接口(Query by Example)。
*
* @param <T> 实体类型
*/
public interface QueryByExampleExecutor<T> {
/**
* 查找与给定示例匹配的单个实体。
*
* @param example 查询条件(封装成 Example)
* @return 匹配的实体(如果存在)
*/
<S extends T> Optional<S> findOne(Example<S> example);
/**
* 查找与给定示例匹配的所有实体。
*
* @param example 查询条件
* @return 匹配的实体集合
*/
<S extends T> Iterable<S> findAll(Example<S> example);
/**
* 查找与示例匹配的所有实体,并排序。
*
* @param example 查询条件
* @param sort 排序条件
* @return 排序后的结果集
*/
<S extends T> Iterable<S> findAll(Example<S> example, Sort sort);
/**
* 查找与示例匹配的所有实体,分页返回。
*
* @param example 查询条件
* @param pageable 分页参数
* @return 分页结果
*/
<S extends T> Page<S> findAll(Example<S> example, Pageable pageable);
/**
* 返回与示例匹配的记录数量。
*
* @param example 查询条件
* @return 匹配数量
*/
<S extends T> long count(Example<S> example);
/**
* 判断是否存在与示例匹配的记录。
*
* @param example 查询条件
* @return 是否存在
*/
<S extends T> boolean exists(Example<S> example);
}
这个接口提供了“示例实体”进行查询的功能
1.8 JpaSpecificationExecutor
package org.springframework.data.jpa.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import java.util.List;
import java.util.Optional;
/**
* 提供使用 JPA Criteria API(即 Specification)进行动态查询的能力。
*
* @param <T> 实体类型
*/
public interface JpaSpecificationExecutor<T> {
/**
* 根据 Specification 返回符合条件的单个实体(最多一个)。
*
* @param spec 查询条件
* @return 匹配的 Optional 实体
*/
Optional<T> findOne(Specification<T> spec);
/**
* 返回所有符合 Specification 的实体列表。
*
* @param spec 查询条件
* @return 匹配的实体集合
*/
List<T> findAll(Specification<T> spec);
/**
* 返回排序后的结果列表。
*
* @param spec 查询条件
* @param sort 排序条件
* @return 排序后的匹配结果
*/
List<T> findAll(Specification<T> spec, Sort sort);
/**
* 返回分页的查询结果。
*
* @param spec 查询条件
* @param pageable 分页条件
* @return 分页结果
*/
Page<T> findAll(Specification<T> spec, Pageable pageable);
/**
* 返回符合 Specification 条件的记录总数。
*
* @param spec 查询条件
* @return 匹配数量
*/
long count(Specification<T> spec);
}
用法示例:
Specification<User> spec = (root, query, cb) ->
cb.equal(root.get("username"), "张三");
List<User> result = userRepository.findAll(spec);
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {}
- 多条件动态查询(表单筛选、后台搜索)
- 多表关联查询时,配合Join
- 条件复杂四时优于@Query和方法名查询
1.9 QuerydslPredicateExecutor
···
package org.springframework.data.querydsl;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.PathBuilder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import java.util.Optional;
public interface QuerydslPredicateExecutor
/**
* 查找符合给定 Predicate 条件的单个实体。
*
* @param predicate 查询条件
* @return 匹配的实体(如果存在)
*/
Optional findOne(Predicate predicate);
/**
* 查找符合给定 Predicate 条件的所有实体。
*
* @param predicate 查询条件
* @return 匹配的所有实体
*/
Iterable findAll(Predicate predicate);
/**
* 按照指定的排序规则返回匹配的所有实体。
*
* @param predicate 查询条件
* @param sort 排序规则
* @return 排序后的匹配实体集合
*/
Iterable findAll(Predicate predicate, Sort sort);
/**
* 按 Querydsl 的 OrderSpecifier 排序。
*
* @param predicate 查询条件
* @param orders 排序规则(Querydsl 专用)
* @return 排序后的匹配实体集合
*/
Iterable findAll(Predicate predicate, OrderSpecifier>... orders);
/**
* 分页查询。
*
* @param predicate 查询条件
* @param pageable 分页参数
* @return 分页结果
*/
Page findAll(Predicate predicate, Pageable pageable);
/**
* 计算符合查询条件的记录数。
*
* @param predicate 查询条件
* @return 记录数量
*/
long count(Predicate predicate);
/**
* 判断是否存在符合查询条件的记录。
*
* @param predicate 查询条件
* @return 是否存在
*/
boolean exists(Predicate predicate);
/**
* 返回当前实体的 PathBuilder(用于构建 Predicate)
*
* @return 路径构建器
*/
PathBuilder getPathBuilder();
}
···
基于Querydsl的类型安群查询机制,功能类似于JpaSpecifiactionExecutor
, 但使用更了流畅、链式的查询方式。
QUser user = QUser.user;
Predicate predicate = user.age.gt(18).and(user.status.eq("ACTIVE"));
Page<User> result = userRepository.findAll(predicate, PageRequest.of(0, 10));
public interface UserRepository
extends JpaRepository<User, Long>, QuerydslPredicateExecutor<User> {}
发表回复