hibernate-使用data jpa
来源:互联网 发布:微信群淘宝优惠券代理 编辑:程序博客网 时间:2024/05/24 07:37
简介
笔者在前面的文章中提及到过 spring-data-jpa ,什么是 jpa ,什么是 spring-data-jpa 。jpa 是 Java Persistence API的简称,是 javaEE 的 orm 规范,spring-data-jpa 是依照 jap 规范的关于数据持久层的一系列接口,在 spring 中是这样介绍 data-jpa 的:spring-data-jpa 是 spring 数据持久层的一部分,能够更轻松方便实现基于 JPA 的库,更容易构建出 spring 应用。说白了,spring-data-jpa 让我们更方便地操作持久层。
使用
1.使用 data-jpa 主要是要使用 spring 提供的一系列 Repository 接口。
// 接口族Repository<T, ID extends Serializable> CrudRepository<T, ID extends Serializable> PagingAndSortingRepository<T, ID extends Serializable> JpaRepository<T, ID extends Serializable>// 用于动态查询 JpaSpecificationExecutor<T>
2.先来看看这些接口声明了那些方法
空接口
public interface Repository<T, ID extends Serializable> {}
CrudRepository 声明了基本的 CRUD 方法
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> { // 保存或更新 <S extends T> S save(S var1); // 批量保存或更新 <S extends T> Iterable<S> save(Iterable<S> var1); // 根据主键查找 T findOne(ID var1); // 根据主键判断是否存在 boolean exists(ID var1); // 查找所有符合条件的 Iterable<T> findAll(); Iterable<T> findAll(Iterable<ID> var1); // 统计总量 long count(); // 根据主键或其他条件删除 void delete(ID var1); void delete(T var1); void delete(Iterable<? extends T> var1); void deleteAll();}
PagingAndSortingRepository 接口继承 CrudRepository ,主要增加了分页和排序功能
public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> { // 排序查找 Iterable<T> findAll(Sort var1); // 分页查找 Page<T> findAll(Pageable var1);}
JpaRepository 接口继承 PagingAndSortingRepository 接口,扩展了一些返回参数类型为 List 的方法
public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> { List<T> findAll(); List<T> findAll(Sort var1); List<T> findAll(Iterable<ID> var1); <S extends T> List<S> save(Iterable<S> var1); void flush(); <S extends T> S saveAndFlush(S var1); void deleteInBatch(Iterable<T> var1); void deleteAllInBatch(); T getOne(ID var1); <S extends T> List<S> findAll(Example<S> var1); <S extends T> List<S> findAll(Example<S> var1, Sort var2);}
JpaSpecificationExecutor 是一个高级动态查询接口,不是 Repository 系列中的子接口
public interface JpaSpecificationExecutor<T> { T findOne(Specification<T> var1); List<T> findAll(Specification<T> var1); Page<T> findAll(Specification<T> var1, Pageable var2); List<T> findAll(Specification<T> var1, Sort var2); long count(Specification<T> var1);}
3.如何使用这些接口,你仅需要继承这些接口即可,具体实现由 data-jpa 库帮你实现,和使用 mybatis 差不过。举个栗子:
@Repositorypublic interface UserRepository extends JpaRepository<User,Long> {}
这样就可以通过 spring 自动注入到类中使用了,你可以调用上述接口中声明的任意方法完成持久化操作。一般上述方法就可以满足一般的需求,但是我们可不可以扩展这些接口呢,答案是可以的,不过在扩展接口时的方法命名需要遵循 data-jpa 的规范约束,例如:
@Repositorypublic interface UserRepository extends JpaRepository<User,Long> { // 根据 userId 查找 user User findByUserId(String userId); // 根据 username 查找 user User findByUsername(String username); User findByUsernameAndAge(String username,int age);}
基本是使用:findBy,deleteBy,countBy,existsBy,orderBy,between ,distinct,and,or…,实体类属性名 等这些关键字拼接起来。当这些都不满足需求时,就可以通过使用 @Query 注解自己拼 hql 了。例如:
@Repositorypublic interface UserRepository extends JpaRepository<User,Long> { User findByUserId(String userId); User findUserByUsername(String username); @Query("select u from User u join u.department dept where dept.departmentId = :deptId") Page<User> findByDeptId(@Param("deptId") String deptId, Pageable pageable); @Query("select u from User u join u.roles role where role.roleId = :roleId") Page<User> findByRoleId(@Param("roleId") Long roleId, Pageable pageable); @Query("select count(u.userId) from User u join u.department dept where dept.departmentId = :deptId") int countByDeptId(@Param("deptId") String deptId); /*注意update需要modifying*/ @Modifying @Query("update User u set u.flag = :flag where u.userId = :userId") int updateUserFlag(@Param("flag") Integer flag, @Param("userId") String userId);}
一般在做联表查询是就需要使用 hql 了,hql 也是面向对象的,实体类等价于对应的表,通过打点访问类中的关联实体类属性即可做到联表。此外,很多时候我们需要动态查询,以上方案 sql 都是固定的,怎样才能动态拼接 sql 实现动态查询呢,这就要使用到 JpaSpecificationExecutor 了。再来看看这个接口的方法:
public interface JpaSpecificationExecutor<T> { T findOne(Specification<T> var1); List<T> findAll(Specification<T> var1); Page<T> findAll(Specification<T> var1, Pageable var2); List<T> findAll(Specification<T> var1, Sort var2); long count(Specification<T> var1);}
在声明的方法中有三个参数:Sort,Pageable ,Specification ,关键是最后的这个。Specification 就是动态拼接的 sql 的数据结构,在使用动态查询,我们需要做的是如何创建 Specification 对象。
public interface Specification<T> { Predicate toPredicate(Root<T> var1, CriteriaQuery<?> var2, CriteriaBuilder var3);}
Specification 也是一个接口,其中仅有一个方法 toPredicate , 实际上 Predicate 才真正是动态拼接 sql 的数据结构。在组装 sql 时,使用的是 root,criteriaQuery,criteriaBuilder 这三个对象。例如:
@Repositorypublic interface UserRepository extends JpaRepository<User,Long>,JpaSpecificationExecutor<User> { public static class Specs{ /** * 根据查询条件构造动态查询sql * username * userId * deptId * roleId * *root : 可以获取实体类中的属性名(等价数据库中的表,列) *criteriaQuery:构建子查询(等价于使用 orderBy,groupBy 等) *criteriaBuilder:构建 predicate 对象,构建 sql 片段 * */ public static Specification<User> newQueryParams(Map<String,String> paramsMap){ return new Specification<User>() { @Override public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { // 创建 Predicate Predicate predicate = criteriaBuilder.conjunction(); // 组装条件 if(StringUtils.isNotBlank(paramsMap.get("username"))){ predicate.getExpressions().add(criteriaBuilder.like(root.<String>get("username") ,"%"+ paramsMap.get("username") + "%")); } if(StringUtils.isNotBlank(paramsMap.get("userId"))){ predicate.getExpressions().add(criteriaBuilder.equal(root.<String>get("userId"),paramsMap.get("userId"))); } if(StringUtils.isNotBlank(paramsMap.get("deptId"))){ // 注意联表的问题 predicate.getExpressions().add(criteriaBuilder.equal(root.get("department").get("departmentId"),paramsMap.get("deptId"))); } if(StringUtils.isNotBlank(paramsMap.get("roleId"))){ predicate.getExpressions().add(criteriaBuilder.equal(root.join("roles", JoinType.LEFT).get("roleId").as(String.class), paramsMap.get("roleId"))); } return predicate; } }; } }}
PS: 在 hibernate 中的级联注解中,一般使用 CascadeType.ALL,如@OneToMany(cascade={CascadeType.ALL}) , 但是往往不需要级联删除,这是可以使用 hibernate 提供的注解:@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
PS : spring-data-example 多看官方栗子,多看官方栗子,多看官方栗子
- hibernate-使用data jpa
- SpringMVC +Hibernate JPA+Spring-data-jpa
- JPA Spring-Data-JPA hibernate mybatis
- spring data jpa和hibernate jpa
- spring data Jpa hibernate实现
- Spring Data JPA 使用
- spring-data-jpa 使用
- spring data jpa使用
- spring-data-jpa 使用
- Spring Data JPA使用
- spring-data-jpa 使用
- springboot-data-jpa使用
- 使用 Spring Data JPA 简化 JPA 开发
- 使用 Spring Data JPA 简化 JPA 开发
- 使用 Spring Data JPA 简化 JPA 开发
- 使用 Spring Data JPA 简化 JPA 开发
- 使用 Spring Data JPA 简化 JPA 开发
- 使用 Spring Data JPA 简化 JPA 开发
- get和post的区别
- SSH与SSM学习之Spring01——介绍、搭建环境与第一个例子
- hibernate-实体类状态
- String转StringBuffer以及String[ ]之间的相互转换
- XPDF安装与使用说明
- hibernate-使用data jpa
- 使用Spring Cloud Consul实现服务的注册和发现
- 西雅图的房子加价到底有多狠?
- 没有相爱,只有相杀:微软和谷歌又撕上了...
- SSH与SSM学习之Spring02——bean元素配置
- java中的Iterator和Iterable 区别
- 1011. A+B和C (15)
- SSH与SSM学习之Spring03——Spring创建对象的方式
- ionic 侧滑菜单