Spring Data JPA-参考文档
文章摘抄spring 官网(https://docs.spring.io/spring-data/jpa/docs/2.2.2.RELEASE/reference/html/#jpa.query-methods.at-query)
JPA 介绍
JPA 全称为 JAVA Persistence API ,JPA 吸取了目前Java 持久化技术的有点,旨在规范、简化Java对象的持久化技术工作。使用JPA持久化对象,并不是依赖于某一个ORM框架
JPA 使用
Working with Spring Data Repositories
CrudRepository
public interface CrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> S save(S entity);
Optional<T> findById(ID primaryKey);
Iterable<T> findAll();
long count();
void delete(T entity);
boolean existsById(ID primaryKey);
// … more functionality omitted.
}
- Saves the given entity.
- Returns the entity identified by the given ID.
- Returns all entities.
- Returns the number of entities.
- Deletes the given entity.
- Indicates whether an entity with the given ID exists.
PagingAndSortingRepository
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
}
官方文档上的示例
PagingAndSortingRepository<User, Long> repository = // … get access to a bean
Page<User> users = repository.findAll(PageRequest.of(1, 20));
//实际开发中,稍微进行了一些优化,可参考如下
/**
* 排序 数组第一个元素: 排序项目名 数组第二个元素: 排序方向
*/
private List<String> sort;
/**
* 转换为PageRequest
*
* @return PageRequest
*/
public PageRequest toPageRequest() {
PageRequest pageRequest;
int page = getPage() - 1;
int count = getCount();
if (CollectionUtils.isEmpty(sort)) {
pageRequest = new PageRequest(page, count);
} else {
pageRequest = new PageRequest(page, count, buildSort());
}
return pageRequest;
}
private Sort buildSort() {
List<Order> orders = new ArrayList<>();
for (int i = 0; i < sort.size(); i += 2) {
orders.add(new Order(Direction.fromString(sort.get(i + 1)),
sort.get(i)));
}
return new Sort(orders);
}
}
Fragments overriding (方法覆盖)
// 实际开发中,Bean对象都有一个共同类
interface CustomizedSave<T> {
<S extends T> S save(S entity);
}
class CustomizedSaveImpl<T> implements CustomizedSave<T> {
public <S extends T> S save(S entity) {
// Your custom implementation
}
}
Querydsl
public interface QuerydslPredicateExecutor<T> {
Optional<T> findById(Predicate predicate);
Iterable<T> findAll(Predicate predicate);
long count(Predicate predicate);
boolean exists(Predicate predicate);
// … more functionality omitted.
}
- Finds and returns a single entity matching the Predicate.
- Finds and returns all entities matching the Predicate.
- Returns the number of entities matching the Predicate.
- Returns whether an entity that matches the Predicate exists.
开发中都会在 DAO 层实现该方法
interface UserRepository extends CrudRepository<User, Long>, QuerydslPredicateExecutor<User> {
}
Impl 中使用 (文档: http://www.querydsl.com/)
Predicate predicate = QUser.user.firstname.eq("Dave").and(QUser.user.lastname.eq("Matthews"))
// 实际开发会用booleanBuilder 做连接,参考如下
BooleanBuilder where = new BooleanBuilder();
if (!StringUtils.isEmpty(id)) {
where.and(QInspectionPlan.inspectionPlan.id.eq(Long.parseLong(id)));
}
return where.getValue();
userRepository.findAll(predicate);
Using @Query
// 使用Bean对象
public interface UserRepository extends JpaRepository<User, Long> {
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
}
// 使用原生sql
public interface UserRepository extends JpaRepository<User, Long> {
// 原生sql中还可以使用,countQuery 进行计数查询
@Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
User findByEmailAddress(String emailAddress);
}
在JPA 1.4以后,支持SpEL 表达式,但是不推荐使用
@Entity
public class User {
@Id
@GeneratedValue
Long id;
String lastname;
}
public interface UserRepository extends JpaRepository<User,Long> {
@Query("select u from #{#entityName} u where u.lastname = ?1")
List<User> findByLastname(String lastname);
}
Modifying Queries
方法上必须添加@Modifying 注解,该注解有一个属性 clearAutomatically ,默认false,如果设置为true,则方法查询后进行修改,再查询的话不会拿到旧数据(实际上清除缓存),根据实际情况,添加该注解
@Modifying
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);
Delete Queries
interface UserRepository extends Repository<User, Long> {
void deleteByRoleId(long roleId);
@Modifying
@Query("delete from User u where user.role.id = ?1")
void deleteInBulkByRoleId(long roleId);
}
对于以上两个删除方法,官方文档是这样介绍的
尽管该deleteByRoleId(…)方法看起来基本上与产生相同的结果deleteInBulkByRoleId(…),但是在执行方法方面,这两个方法声明之间存在重要区别。顾名思义,后一种方法针对数据库发出单个JPQL查询(在批注中定义的查询)。这意味着即使当前加载的实例User也看不到生命周期回调。
为了确保生命周期查询被实际调用,调用会deleteByRoleId(…)执行一个查询,然后一个接一个地删除返回的实例,以便持久性提供程序实际上可以@PreRemove在这些实体上调用回调。
实际上,前者查询是执行查询,然后调用CrudRepository.delete(Iterable users)结果并使其行为与中其他delete(…)方法的实现保持同步的快捷方式CrudRepository。