什么是jpa
JPA (The Java Persistence API)是用于访问,持久化和管理 Java 对象/类与关系型数据库之间的数据交互的 Java 规范。JPA 被定义为EJB (Enterprise JavaBeans) 3.0规范的一部分,作为 EJB 2 CMP 实体 Bean 规范的替代。
注意,JPA 只是一个标准,只定义了一系列接口,而没有具体的实现。很多企业级框架提供了对 JPA 的实现,如 Spring 。因此 Spring 本身与 JPA 无关,只是提供了对 JPA 的支持,因此在 Spring 中你也会看到很多注解都是属于 javax.persistence 包的。
JPA 允许 POJO(Plain Old Java Objects)轻松地持久化,而不需要类来实现 EJB 2 CM P规范所需的任何接口或方法。 JPA 还允许通过注解或 XML 定义对象的关系映射,定义 Java 类如何映射到关系数据库表。 JPA 还定义了一个运行时 EntityManager API,用于处理对象的查询和管理事务。 同时,JPA 定义了对象级查询语言 JPQL,以允许从数据库中查询对象,实现了对数据库的解耦合,提高了程序的可移植性,而不具体依赖某一底层数据库。
JPA 是 Java 持久化规范中的一个最新版本。第一个版本是 OMG 持久性服务 Java 绑定,但这个一个失败的产品,甚至没有任何商业产品支持它。接下来的版本是 EJB 1.0 CMP Entity Beans,它已经非常成功地被大型 Java EE 提供程序(BEA,IBM)采用,但是它复杂性太高而且性能比较差。EJB 2.0 CMP 试图通过引入本地接口来减少 Entity Bean 的一些复杂性,但是大多数复杂性仍然存在,而且缺乏可移植性。
历史总是要向前发展的,种种的这些使得 EJB 3.0 规范将降低复杂性作为主要目标,这导致规范委员会沿着 JPA 的路径前进。 JPA 旨在统一 EJB 2 CMP,JDO,Hibernate,从目前来看,JPA 的确取得了成功。
目前大多数持久化供应商已经发布了 JPA 的实现,并被行业和用户采用。这些包括 Hibernate(由 JBoss 和 Red Hat 收购),TopLink(由 Oracle 收购)和 Kodo JDO(由 BEA 和 Oracle 收购)。其他支持 JPA 的产品包括 Cocobase(由 Thought Inc. 收购)和 JPOX。
Spring Boot JPA - 基本使用
导入jar
在pom.xml中加入依赖
1 <dependency>
2 <groupId>org.springframework.boot</groupId>
3 <artifactId>spring-boot-starter-data-jpa</artifactId>
4 </dependency>
复制代码
创建实体
1@Entity
2public class User{
3
4
5 @Id
6 @GeneratedValue(strategy = GenerationType.IDENTITY)
7 private Integer id;
8
9 private String phone;
10
11
12 public String getPhone() {
13 return phone;
14 }
15
16 public void setPhone(String phone) {
17 this.phone = phone;
18 }
19}
复制代码
Dao层接口
1public interface UserDao extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> {
2
3 User findByPhone(String phone);
4
5 User findByPhoneAndFlag(String phone, Integer flag);
6
7 User findByIdAndFlag(Integer userId, Integer flag);
8
9 User findByOpenIdAndFlag(String openId, Integer flag);
10
11 Page<User> findByFlag(Integer flag, Pageable pageable);
12
13 List<User> findByNewPersonAndFlagOrderByCreateTimeAsc(Integer isNewPerson, Integer flag);
14
15 User findById(Integer toBeFollowID);
16
17 List<User> findByFlagAndNewPerson(Integer flag, Integer isNewPerson, Pageable pageable);
18
19 List<User> findByNicenameIsLikeAndFlagAndNewPerson(String searchName, Integer flag, Integer isNewPerson, Pageable pageable);
20
21}
复制代码
spring data jpa 默认预先生成了一些基本的CURD的方法,例如:增、删、改等等
1 userDao.save(user); //保存一个对象
2 userDao.save(new List<User>); //保存多个对象
3 userDao.delete(user); //删除一个对象
4 userDao.delete(id); //通过id删除
5 userDao.deleteAll(); //删除所有
6 userDao.delete(new ArrayList<>()); //批量删除
7 userDao.findOne(id); //通过id获取
8 userDao.getOne(id); //通过id获取 不推荐使用
9 userDao.findAll(pageable); //分页查找所有
10 userDao.exists(id); //id是否存在
11 ......
复制代码
除此之外还提供了自定义方法名的方式查询(在userDao中)
1User findByOpenIdAndFlag(String openId, Integer flag);
2//等同于
3SELECT * FROM 'user' WHERE open_id =?1 AND flag = ?2
复制代码
具体的关键字,使用方法和生产成SQL如下表所示
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | where x.firstname = 1? |
Between | findByStartDateBetween | where x.startDate between 1? and ?2 |
LessThan | findByAgeLessThan | where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | where x.age <= ?1 |
GreaterThan | findByAgeGreaterThan | where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | where x.age >= ?1 |
After | findByStartDateAfter | where x.startDate > ?1 |
Before | findByStartDateBefore | where x.startDate < ?1 |
IsNull | findByAgeIsNull | where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | where x.age not null |
Like | findByFirstnameLike | where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | where x.firstname like ?1 |
EndingWith | findByFirstnameEndingWith | where x.firstname like ?1 |
Containing | findByFirstnameContaining | where x.firstname like ?1 |
OrderBy | findByAgeOrderByLastnameDesc | where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | where x.lastname <> ?1 |
In | findByAgeIn(Collection<Age> ages) | where x.age in ?1 |
NotIn | findByAgeNotIn(Collection<Age> age) | where x.age not in ?1 |
True | findByActiveTrue() | where x.active = true |
False | findByActiveFalse() | where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | where UPPER(x.firstame) = UPPER(?1) |
分页查询
直接在controller层封装好Pageable对象即可
1@GetMapping("findBanners")
2public Page<Banner> findBanners(@PageableDefault(sort = {"priority"}, direction=Sort.Direction.ASC) Pageable pageable)
复制代码
==注意: #ad1f1f==
前端直接在请求的最后拼接上?page=0&size=10
如果前端不传page 和 size 这两个参数过来,那么@PageableDefault会默认为第1页开始,每页最大条数为10。需注意page为0时为第一页。
在service中调用即可
1//返回给客户端的Page对象,其json格式为
2{
3 "content": [],//数据内容
4 "first": true,//是否为第一页
5 "last": true,//是否为最后一页
6 "number": 0,//当前页码
7 "numberOfElements": 0,//当前页中的实际数据条数
8 "size": 0,//一页最大条数
9 "sort": { },//排序信息
10 "totalElements": 0,//总条数
11 "totalPages": 0//总页数
12}
复制代码
自定义分页
1public Page<Banner> findBanners(int id){
2 int page = 1;
3 int size = 10;
4 Sort sort = new Sort(Sort.Direction.DESC,"priority");
5 Pageable pageable = new PageRequest(page,size,sort);
6 return bannserDao.findById(id,pageable);
7 }
复制代码
动态查询
1public Page<Admin> findAdminList(AdminCmsSearchVO adminCmsSearchVO, Pageable pageable) {
2 Specifications<Admin> spec = Specifications.where(commonSpecUtil.like("name", adminCmsSearchVO.getName()))
3 .and(commonSpecUtil.equal("clazzType", adminCmsSearchVO.getClazzType()))
4 .and(commonSpecUtil.equal("flag",ModelContants.AdminContant.FLAG_IS_TRUE));
5 return adminDao.findAll(spec, pageable);
6 }
复制代码
1//(此代码由建东提供)
2package com.luwei.common.utils;
3
4import org.springframework.data.jpa.domain.Specification;
5import org.springframework.stereotype.Component;
6
7import java.util.Date;
8import java.util.List;
9
10/**
11 * Created by jdq on 2017/8/8.
12 */
13@Component
14public class CommonSpecUtil<T> {
15
16 /**
17 * 精确匹配(equal)
18 *
19 * @param srcName 字段名
20 * @param targetProperty 匹配内容
21 * @return
22 */
23 public Specification<T> equal(String srcName, Object targetProperty) {
24 if (targetProperty == null) {
25 return null;
26 }
27 return (root, query, cb) -> cb.equal(root.get(srcName), targetProperty);
28 }
29
30 /**
31 * 精确匹配(notEqual)
32 *
33 * @param srcName 字段名
34 * @param targetProperty 匹配内容
35 * @return
36 */
37 public Specification<T> notEqual(String srcName, Object targetProperty) {
38 if (targetProperty == null) {
39 return null;
40 }
41 return (root, query, cb) -> cb.notEqual(root.get(srcName), targetProperty);
42 }
43
44 /**
45 * 模糊匹配(like)
46 *
47 * @param srcName 字段名
48 * @param targetProperty 匹配内容
49 * @return
50 */
51 public Specification<T> like(String srcName, String targetProperty) {
52 if (StringUtils.isEmpty(targetProperty)) {
53 return null;
54 }
55 return (root, query, cb) -> cb.like(root.get(srcName), "%" + targetProperty + "%");
56 }
57
58 /**
59 * 日期范围匹配(timeBetween)
60 *
61 * @param srcName 字段名
62 * @param startTimeStr 开始时间
63 * @param endTimeStr 结束时间
64 * @return
65 */
66 public Specification<T> timeBetween(String srcName, String startTimeStr, String endTimeStr) {
67 Date startTime, endTime;
68 if (StringUtils.isEmpty(startTimeStr)) {
69 startTime = DateUtils.getDate2("1970-01-01 00:00:00");
70 } else {
71 startTime = DateUtils.getDate2(startTimeStr + " 00:00:00");
72 }
73
74 if (StringUtils.isEmpty(endTimeStr)) {
75 endTime = new Date();
76 } else {
77 endTime = DateUtils.getDate2(endTimeStr + " 23:59:59");
78 }
79 return (root, query, cb) -> cb.between(root.get(srcName), startTime, endTime);
80 }
81
82 public Specification<T> parkingOrderTime(String srcName,String startTimeStr,String endTimeStr) {
83 Date startTime,endTime;
84 startTime=DateUtils.getDate2(DateUtils.tostartDayTime(startTimeStr));
85 endTime = DateUtils.getDate2(DateUtils.toEndDayTime(endTimeStr));
86
87 return (root, query, cb) -> cb.between(root.get(srcName), startTime,endTime);
88 }
89
90
91 /**
92 * 日期范围匹配(timeBetween)
93 *
94 * @param srcName 字段名
95 * @param startTime 开始时间
96 * @param endTime 结束时间
97 * @return
98 */
99 public Specification<T> timeBetween(String srcName, Date startTime, Date endTime) {
100 if (org.springframework.util.StringUtils.isEmpty(startTime)) {
101 return null;
102 }
103 if (org.springframework.util.StringUtils.isEmpty(endTime)) {
104 return null;
105 }
106 return (root, query, cb) -> cb.between(root.get(srcName), startTime, endTime);
107 }
108
109 /**
110 * 数值范围匹配(between)
111 *
112 * @param srcName 字段名
113 * @param start 开始
114 * @param end 结束
115 * @return
116 */
117 public Specification<T> between(String srcName, Integer start, Integer end) {
118 if (org.springframework.util.StringUtils.isEmpty(start)) {
119 return null;
120 }
121 if (org.springframework.util.StringUtils.isEmpty(end)) {
122 return null;
123 }
124 return (root, query, cb) -> cb.between(root.get(srcName), start, end);
125 }
126
127 /**
128 * 大于等于(greaterThanOrEqualTo)
129 *
130 * @param srcName 字段名
131 * @param value 数值
132 * @return
133 */
134 public Specification<T> greaterThanOrEqualTo(String srcName, Integer value) {
135 if (org.springframework.util.StringUtils.isEmpty(value)) {
136 return null;
137 }
138 return (root, query, cb) -> cb.greaterThanOrEqualTo(root.get(srcName), value);
139 }
140
141 /**
142 * 小于等于(lessThanOrEqualTo)
143 *
144 * @param srcName 字段名
145 * @param value 数值
146 * @return
147 */
148 public Specification<T> lessThanOrEqualTo(String srcName, Integer value) {
149 if (org.springframework.util.StringUtils.isEmpty(value)) {
150 return null;
151 }
152 return (root, query, cb) -> cb.lessThanOrEqualTo(root.get(srcName), value);
153 }
154
155 /**
156 * in条件帅选(in)
157 *
158 * @param srcName 字段名
159 * @param list 集合
160 * @return
161 */
162 public Specification<T> in(String srcName, List<Integer> list) {
163 if (org.springframework.util.StringUtils.isEmpty(list)) {
164 return null;
165 }
166 return (root, query, cb) -> cb.and(root.get(srcName).in(list));
167 }
168
169 /**
170 * 不为空(isNotNull)
171 *
172 * @param srcName 字段名
173 * @return
174 */
175 public Specification<T> isNotNull(String srcName) {
176 return (root, query, cb) -> cb.isNotNull(root.get(srcName));
177 }
178
179 /**
180 * 倒序(desc)
181 *
182 * @param srcName 字段名
183 * @return
184 */
185 public Specification<T> desc(String srcName) {
186 return (root, query, cb) -> query.orderBy(cb.desc(root.get(srcName).as(Integer.class))).getRestriction();
187 }
188
189 /**
190 * 升序(asc)
191 *
192 * @param srcName 字段名
193 * @return
194 */
195 public Specification<T> asc(String srcName) {
196 return (root, query, cb) -> query.orderBy(cb.asc(root.get(srcName).as(Integer.class))).getRestriction();
197 }
198
199}
复制代码
动态查找的条件:
1.adminDao要继承JpaSpecificationExecutor
2.CommonSpecUtil提供了各种匹配的方法。如equals,like,notEqual……
参考博客
部分引用于袁荻的博客
原文地址
掘金 | segmentfault | V2EX | 知乎 | 博客园 | 开源中国 | github | 简书 | 芦苇科技 |
广州芦苇科技Java开发团队
芦苇科技-广州专业软件外包服务公司
提供微信小程序、APP应用研发、UI设计等专业服务,专注于互联网产品咨询、品牌设计、技术研发等领域
访问 www.talkmoney.cn 了解更多
万能说明书 | 早起日记Lite | 凹凸壁纸 | 言财