Spring data JPA使用详解(超详细)

本文详述了Spring Data JPA的使用,包括Repository接口、CrudRepository、PagingAndSortingRepository、JpaRepository和JpaSpecificationExecutor接口。重点介绍了JpaSpecificationExecutor接口,解释了Criteria查询的概念,如CriteriaQuery、Root、Predicate等,并提供了多表连接查询的示例。此外,还探讨了Spring Data JPA的查询方式,如@Query、@NamedQueries和通过解析方法名创建查询。文章最后提到了Spring Data JPA对事务的支持和默认处理方式。
摘要由CSDN通过智能技术生成

目录
Jpa
元模型
Criteria查询
CriteriaBuilder 安全查询创建工厂
CriteriaQuery 安全查询主语句
Root
Predicate 过滤条件
Predicate 多个过滤条件

jpa

Spring data JPA简介
Spring data JPA是Spring在ORM框架,以及JPA规范的基础上,封装的一套JPA应用框架,并提供了一整套的数据访问层解决方案。
Spring data JPA提供给用户使用的,主要有以下几个接口:
Repository:仅仅是一个标识,表明任何继承它的均为仓库接口类,方便Spring自动扫描识别
CrudRepository:继承Repository,实现了一组CRUD相关的方法
PagingAndSortingRepository:继承CrudRepository,实现了一组分页排序相关的方法
JpaRepository:继承PagingAndSortingRepository,实现一组JPA规范相关的方法
JpaSpecificationExecutor:比较特殊,不属于Repository体系,实现一组JPA Criteria查询相关的方法
JpaSpecificationExecutor接口
该接口提供了对JPA Criteria查询的支持。注意,这个接口很特殊,不属于Repository体系,而Spring data JPA不会自动扫描识别,所以会报找不到对应的Bean,我们只需要继承任意一个继承了Repository的子接口或直接继承Repository接口,Spring data JPA就会自动扫描识别,进行统一的管理。
Criteria 查询:是一种类型安全和更面向对象的查询
这个接口基本是围绕着Specification接口来定义的, Specification接口中只定义了如下一个方法:

Predicate toPredicate(Root<T> root,CriteriaQuery<?> query, CriteriaBuilder cb);

要理解这个方法,以及正确的使用它,就需要对JPA2.0的Criteria查询有一个足够的熟悉和理解,因为这个方法的参数和返回值都是JPA标准里面定义的对象。
Criteria查询基本概念
Criteria 查询是以元模型的概念为基础的,元模型是为具体持久化单元的受管实体定义的,这些实体可以是实体类,嵌入类或者映射的父类。
CriteriaQuery接口:代表一个specific的顶层查询对象,它包含着查询的各个部分,比如:select 、from、where、group by、order by等
注意:CriteriaQuery对象只对实体类型或嵌入式类型的Criteria查询起作用
Root接口:代表Criteria查询的根对象,Criteria查询的查询根定义了实体类型,能为将来导航获得想要的结果,它与SQL查询中的FROM子句类似:
1:Root实例是类型化的,且定义了查询的FROM子句中能够出现的类型。
2:查询根实例能通过传入一个实体类型给 AbstractQuery.from方法获得。
3:Criteria查询,可以有多个查询根。
4:AbstractQuery是CriteriaQuery 接口的父类,它提供得到查询根的方法。
CriteriaBuilder接口:用来构建CritiaQuery的构建器对象
Predicate:一个简单或复杂的谓词类型,其实就相当于条件或者是条件组合。
Criteria查询
基本对象的构建
1:通过EntityManager的getCriteriaBuilder或EntityManagerFactory的getCriteriaBuilder方法可以得到CriteriaBuilder对象
2:通过调用CriteriaBuilder的createQuery或createTupleQuery方法可以获得CriteriaQuery的实例
3:通过调用CriteriaQuery的from方法可以获得Root实例
过滤条件
1:过滤条件会被应用到SQL语句的FROM子句中。在criteria 查询中,查询条件通过Predicate或Expression实例应用到CriteriaQuery对象上。
2:这些条件使用 CriteriaQuery.where 方法应用到CriteriaQuery 对象上
3:CriteriaBuilder也作为Predicate实例的工厂,通过调用CriteriaBuilder 的条件方法( equal,notEqual, gt, ge,lt, le,between,like等)创建Predicate对象。
4:复合的Predicate 语句可以使用CriteriaBuilder的and, or andnot 方法构建。
构建简单的Predicate示例:

Predicate p1=cb.like(root.get(“name”).as(String.class),%+uqm.getName()+%);
Predicate p2=cb.equal(root.get("uuid").as(Integer.class), uqm.getUuid());
Predicate p3=cb.gt(root.get("age").as(Integer.class), uqm.getAge());

构建组合的Predicate示例:

Predicate p = cb.and(p3,cb.or(p1,p2));

当然也可以形如前面动态拼接查询语句的方式,比如:

1.  Specification<UserModel> spec = new Specification<UserModel>() {
     
2.  public Predicate toPredicate(Root<UserModel> root,  
3.          CriteriaQuery<?> query, CriteriaBuilder cb) {
     
4.      List<Predicate> list = new ArrayList<Predicate>();  
5.            
6.      if(um.getName()!=null && um.getName().trim().length()>0){
     
7.          list.add(cb.like(root.get("name").as(String.class), "%"+um.getName()+"%"));  
8.      }  
9.      if(um.getUuid()>0){
     
10.         list.add(cb.equal(root.get("uuid").as(Integer.class), um.getUuid()));  
11.     }  
12.     Predicate[] p = new Predicate[list.size()];  
13.     return cb.and(list.toArray(p));  
14. }  
15. };  

也可以使用CriteriaQuery来得到最后的Predicate,示例如下:

1.     Specification<UserModel> spec = new Specification<UserModel>() {
     
2.         public Predicate toPredicate(Root<UserModel> root,  
3.                 CriteriaQuery<?> query, CriteriaBuilder cb) {
     
4.             Predicate p1 = cb.like(root.get("name").as(String.class), "%"+um.getName()+"%");  
5.             Predicate p2 = cb.equal(root.get("uuid").as(Integer.class), um.getUuid());  
6.             Predicate p3 = cb.gt(root.get("age").as(Integer.class), um.getAge());  
7.             //把Predicate应用到CriteriaQuery中去,因为还可以给CriteriaQuery添加其他的功能,比如排序、分组啥的  
8.             query.where(cb.and(p3,cb.or(p1,p2)));  
9.             //添加排序的功能  
10.         query.orderBy(cb.desc(root.get("uuid").as(Integer.class)));  
11.            
12.         return query.getRestriction();  
13.      }  
14. };  

多表联接

n多表连接查询稍微麻烦一些,下面演示一下常见的1:M,顺带演示一下1:1

n使用Criteria查询实现1对多的查询

1:首先要添加一个实体对象DepModel,并设置好UserModel和它的1对多关系,如下:

@Entity
@Table(name="tbl_user")
public class UserModel {
   
@Id
private Integer uuid;
private String name;
private Integer age;
@OneToMany(mappedBy = "um", fetch= FetchType. LAZY, cascade = {
   CascadeType. ALL})
private Set<DepModel> setDep;
//省略getter/setter
}
@Entity
@Table(name="tbl_dep")
public class DepModel {
   
@Id
private Integer uuid;
private String name;
@ManyToOne()
  @JoinColumn(name ="user_id", nullable = false)
//表示在tbl_dep里面有user_id的字段
private UserModel um = new UserModel();
//省略getter/setter
}

2:配置好Model及其关系后,就可以在构建Specification的时候使用了,示例如下:

Specification<UserModel> spec = newSpecification<UserModel>() {
   
public PredicatetoPredicate(Root<UserModel> root, CriteriaQuery<?> query,CriteriaBuilder cb) {
   
Predicate p1 =cb.like(root.get("name").as(String.class),"%"+um.getName()+"%");
Predicate p2 =cb.equal(root.get("uuid").as(Integer.class), um.getUuid());
Predicate p3 =cb.gt(root.get("age").as(Integer.class), um.getAge());
SetJoin<UserModel,DepModel> depJoin =root.join(root.getModel().getSet("setDep",DepModel.class) ,JoinType.LEFT);
Predicate p4 =cb.equal(depJoin.get("name").as(String.class), "ddd");
//把Predicate应用到CriteriaQuery去,因为还可以给CriteriaQuery添加其他的功能,比如排序、分组啥 的
query.where(cb.and(cb.and(p3,cb.or(p1,p2)),p4));
//添加分组的功能
query.orderBy(cb.desc(root.get("uuid").as(Integer.class)));
return query.getRestriction();
}};

接下来看看使用Criteria查询实现1:1的查询

1:在UserModel中去掉setDep的属性及其配置,然后添加如下的属性和配置:

@OneToOne()
@JoinColumn(name = "depUuid")
private DepModel dep;
public DepModel getDep() {
    return dep;}
public void setDep(DepModel dep) {
   this.dep= dep;  }

2:在DepModel中um属性上的注解配置去掉,换成如下的配置:

@OneToOne(mappedBy = "dep", fetch= FetchType. EAGER, cascade = {
   CascadeType. ALL})

3:在Specification实现中,把SetJoin的那句换成如下的语句:

Join<UserModel,DepModel> depJoin =
root.join(root.getModel().getSingularAttribute("dep",DepModel.class),JoinType.LEFT);
//root.join(“dep”,JoinType.LEFT); //这句话和上面一句的功能一样,更简单

编写接口如下:

1.     public interface SpecificationExecutonExeorRepository extends CrudRepository<User, Integer>,  JpaSpecificaticutor<User> {
   }  

Service类:

1.     @Service  
2.     public class SpecificationExecutorRepositoryManager {
     
3.         @Autowired  
4.         private SpecificationExecutorRepository dao;  
5.         /** 
6.          * 描述:根据name来查询用户 
7.          */  
8.         public User findUserByName(final String name){
     
9.             return dao.findOne(new Specification<User>() {
     
10.               
11.              @Override  
12.             public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query,  
13.                      CriteriaBuilder cb) {
     
14.                 Predicate predicate = cb.equal(root.get("name"), name);  
15.                  return predicate;  
16.             }  
17.          });  
18.     }  
19.        
20.     /** 
21.       * 描述:根据name和email来查询用户 
22.      */  
23.      public User findUserByNameAndEmail(final String name, final String email){
     
24.         return dao.findOne(new Specification<User>() {
     
25.                
26.             @Override  
27.              public Predicate toPredicate(Root<User> root,  
28.                     CriteriaQuery<?> query, CriteriaBuilder cb) {
     
29.                  List<Predicate> list = new ArrayList<Predicate>();  
30.                 Predicate predicate1 = cb.equal(root.get("name"), name);  
31.                  Predicate predicate2 = cb.equal(root.get("email"), email);  
32.                 list.add(predicate1);  
33.                  list.add(predicate2);  
34.                 // 注意此处的处理  
35.                  Predicate[] p = new Predicate[list.size()];  
36.                 return cb.and(list.toArray(p));  
37.              }  
38.         });  
39.      }  
40.       
41.      /** 
42.      * 描述:组合查询 
43.       */  
44.     public User findUserByUser(final User userVo){
     
45.          return dao.findOne(new Specification<User>() {
     
46.               
47.              @Override  
48.             public Predicate toPredicate(Root<User> root,  
49.                      CriteriaQuery<?> query, CriteriaBuilder cb) {
     
50.                 Predicate predicate = cb.equal(root.get("name"), userVo.getName());  
51.                  cb.and(predicate, cb.equal(root.get("email"), userVo.getEmail()));  
52.                 cb.and(predicate, cb.equal(root.get("password"), userVo.getPassword()));  
53.                  return predicate;  
54.             }  
55.          });  
56.     }  
57.        
58.     /** 
59.       * 描述:范围查询in方法,例如查询用户id在[2,10]中的用户 
60.      */  
61.      public List<User> findUserByIds(final List<Integer> ids){
     
62.         return dao.findAll(new Specification<User>() {
     
63.    
64.             @Override  
65.              public Predicate toPredicate(Root<User> root,  
66.                     CriteriaQuery<?> query, CriteriaBuilder cb) {
     
67.                  return root.in(ids);  
68.             }  
69.          });  
70.     }  
71.        
72.     /** 
73.       * 描述:范围查询gt方法,例如查询用户id大于9的所有用户 
74.      */  
75.      public List<User> findUserByGtId(final int id){
     
76.         return dao.findAll(new Specification<User>() {
     
77.    
78.             @Override  
79.              public Predicate toPredicate(Root<User> root,  
80.                     CriteriaQuery<?> query, CriteriaBuilder cb) {
     
81.                  return cb.gt(root.get("id").as(Integer.class), id);  
82.             }  
83.          });  
84.     }  
85.        
86.     /** 
87.       * 描述:范围查询lt方法,例如查询用户id小于10的用户 
88.      */  
89.      public List<User> findUserByLtId(final int id){
     
90.         return dao.findAll(new Specification<User>() {
     
91.    
92.             @Override  
93.              public Predicate toPredicate(Root<User> root,  
94.                     CriteriaQuery<?> query, CriteriaBuilder cb) {
     
95.                  return cb.lt(root.get("id").as(Integer.class), id);  
96.             }  
97.          });  
98.     }  
99.        
100.       /** 
101.        * 描述:范围查询between方法,例如查询id在3和10之间的用户 
102.        */  
103.       public List<User> findUserBetweenId(final int start, final int end){
     
104.           return dao.findAll(new Specification<User>() {
     
105.     
106.               @Override  
107.               public Predicate toPredicate(Root<User> root,  
108.                       CriteriaQuery<?> query, CriteriaBuilder cb) {
     
109.                   return cb.between(root.get("id").as(Integer.class), start, end);  
110.               }  
111.           });  
112.       }  
113.         
114.       /** 
115.        * 描述:排序和分页操作 
116.        */  
117.       public Page<User> findUserAndOrder(final int id){
     
118.           Sort sort = new Sort(Direction.DESC, "id");  
119.           return dao.findAll(new Specification<User>() {
     
120.     
121.               @Override  
122.               public Predicate toPredicate(Root<User> root,  
123.                       CriteriaQuery<?> query, CriteriaBuilder cb) {
     
124.                   return cb.gt(root.get("id").as(Integer.class), id);  
125.               }  
126.           }, new PageRequest(0, 5, sort));  
127.       }  
128.         
129.       /** 
130.        * 描述:只有排序操作 
131.        */  
132.       public List<User> findUserAndOrderSecondMethod(final int id){
     
133.           return dao.findAll(new Specification<User>() {
     
134.     
135.               @Override  
136.               public Predicate toPredicate(Root<User> root,  
137.                       CriteriaQuery<?> query, CriteriaBuilder cb) {
     
138.                   cb.gt(root.get("id").as(Integer.class), id);  
139.                   query.orderBy(cb.desc(root.get("id").as(Integer.class)));  
140.                   return query.getRestriction();  
141.               }  
142.           });  
143.       }  
144.   }  

测试类:

1.     @RunWith
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值