JPA本身并不是一种框架,是一种规范,其全称是Java Persistence API,是是Sun官方提出的Java持久化规范,而他的出现主要是为了简化现有的持久化开发工作和整合ORM技术,并且其是在充分吸收了现有Hibernate,TopLink,JDO等ORM框架的基础上发展而来的,具有易于使用,伸缩性强等优点。
Spring Data JPA的官网对介绍:Spring Data JPA是Spring Data系列的一部分,可以轻松实现基于JPA的存储库。该模块处理对基于JPA的数据访问层的增强的支持。这使得使用数据访问技术构建Spring供电的应用程序变得更加容易。
Spring Data JPA旨在通过减少实际需要的数量来显着提高数据访问层的实现。作为开发人员,您编写存储库接口(包括自定义查找器方法),Spring将自动提供实现。
主要特点:
关键字 | 示例 | 说明 | JPQL片段示例 |
---|---|---|---|
|
|
并且 |
|
|
|
或 |
|
|
|
等于 |
|
|
|
两者之间 |
|
|
|
小于 |
|
|
|
小于等于 |
|
|
|
大于 |
|
|
|
大于等于 |
|
|
|
之后(时间) |
|
|
|
之前(时间) |
|
|
|
等于Null |
|
|
|
不等于Null |
|
|
|
模糊查询。查询件中需要自己加 % |
|
|
|
不在模糊范围内。查询件中需要自己加 % |
|
|
|
以某开头 |
|
|
|
以某结束 |
|
|
|
包含某 |
|
|
|
排序 |
|
|
|
不等于 |
|
|
|
某范围内 |
|
|
|
某范围外 |
|
|
|
真 |
|
|
|
假 |
|
|
|
忽略大小写 |
|
规则描述
按照Spring data 定义的规则,查询方法以find|read|get开头(比如 find、findBy、read、readBy、get、getBy),涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写。框架在进行方法名解析时,会先把方法名多余的前缀截取掉,然后对剩下部分进行解析。
如果方法的最后一个参数是 Sort 或者 Pageable 类型,也会提取相关的信息,以便按规则进行排序或者分页查询。
举例说明
比如 findByUserAddressZip()。框架在解析该方法时,首先剔除 findBy,然后对剩下的属性进行解析,详细规则如下(此处假设该方法针对的域对象为 AccountInfo 类型):
可能会存在一种特殊情况,比如 AccountInfo 包含一个 user 的属性,也有一个 userAddress 属性,此时会存在混淆。读者可以明确在属性之间加上 "_" 以显式表达意图,比如 "findByUser_AddressZip()" 或者 "findByUserAddress_Zip()"。(强烈建议:无论是否存在混淆,都要在不同类层级之间加上"_" ,增加代码可读性)
当查询条件为null时。
举例说明如下:
排序
List findBySexOrderByName(String sex); //名称正序(正序时,推荐此方式,简单)
List findBySexOrderByNameAsc(String sex); //名称正序(效果同上)
List findBySexOrderByNameDesc(String sex); //名称倒序
结果限制
/**
* 根据父ID,得到排序号最大的bo。
* 用于预计算新资源的排序号。
*/
Resource findFirstByFather_idOrderByOrderNumDesc(Long fatherId);
User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page queryFirst10ByLastname(String lastname, Pageable pageable);
Slice findTop3ByLastname(String lastname, Pageable pageable);
List findFirst10ByLastname(String lastname, Sort sort);
List findTop10ByLastname(String lastname, Pageable pageable);
Spring Data JPA使用findAllOrderBy坑
List findAllOrderByCreateTimeDesc();
可以看到,我希望在一个表中查询所有的数据,并按照createTime
这个字段进行排序,这样的写法看似正确的,会报错
其实,正确的写法是:
List findAllByOrderByCreateTimeDesc();
4、计数
Long count();
Long countByLastname(String lastname);
5、删除
void deleteByProject_Id(Long id);
void deleteByProject_Cus_id(Long id);
刚开始使用springdata的时候,只会用findByName这样的简单查询,这样写dao层确实非常的快,但是在我们做筛选功能的时候,这样的查询似乎很难满足我们的需求,但是都已经用上的springdata又不想再去写mybatis这样在xml里面判断是否为Null。
我们首先会想到可以使用@Query注解,这种方式可以直接在Repository里面写sql,但是这种方式的问题就是太麻烦了,而且非常容易出错,扩展性也很差,还不如直接用mybatis。
用example可以最快速的完成支持所有参数的筛选功能,像这样的代码:
/**
* 查询用户列表
*
* @return 用户列表
*/
@GetMapping("listByKeyWord")
public String list(ModelMap model, OyUser user) {
//创建匹配器,即如何使用查询条件
ExampleMatcher matcher = ExampleMatcher.matching()
//模糊查询匹配开头,即{username}% .withMatcher("nickName", ExampleMatcher.GenericPropertyMatchers.startsWith())
.withMatcher("nickName", ExampleMatcher.GenericPropertyMatchers.contains())
//全部模糊查询,即%{address}%
.withMatcher("name" ,ExampleMatcher.GenericPropertyMatchers.contains())
.withMatcher("account" ,ExampleMatcher.GenericPropertyMatchers.contains())
//忽略字段,即不管password是什么值都不加入查询条件
.withIgnorePaths("sex","age")
// 忽略属性:id。因为是基本类型,需要忽略掉
.withIgnorePaths("id");
//创建实例
Example example = Example.of(user ,matcher);
//查询
List userList = oyUserRepository.findAll(example);
model.put("users",userList);
return "user";
}
Example会将为null的字段自动过滤掉,不会作为筛选条件,ExampleMatch是为了支持一些稍微复杂一些的查询,比如如果有int类型的id就需要用withIgnorePaths()忽略掉,因为Int类型默认为0,而不是Null。
如果只是简单的字符串匹配的话,可以直接用:
Example
限制
Criteria查询是Jpa中最强的使用方式了,所有的场景应该都能完成。
首先Repository要继承JpaSpecificationExecutor:
public interface OyUserRepository extends JpaRepository , JpaSpecificationExecutor {
}
然后就是构造动态查询:
/**
* 查询用户列表2
*
* @return 用户列表
*/
@GetMapping("listByKeyWord2")
public String listByKeyWord2(ModelMap model, OyUser oyUser) {
Specification querySpeci = new Specification() {
@Override
public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
List predicates = new ArrayList();
if (oyUser.getName() != null) {
predicates.add(criteriaBuilder.like(root.get("name"), "%" + oyUser.getName() + "%"));
}
if (oyUser.getAccount() != null) {
predicates.add(criteriaBuilder.like(root.get("account"), "%" + oyUser.getAccount() + "%"));
}
if (null != oyUser.getAge()) {
predicates.add(criteriaBuilder.gt(root.get("age"), oyUser.getAge()));
}
if (null != oyUser.getSex()) {
predicates.add(criteriaBuilder.equal(root.get("sex"), oyUser.getSex()));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
}
};
Pageable pageable = PageRequest.of(0, 3);
Page userListPage = oyUserRepository.findAll(querySpeci, pageable);
model.put("users", userListPage.getContent());
return "user";
}
其他
@Resource
private EntityManager entityManager;
/**
* 查询用户列表1
*
* @return 用户列表
*/
@GetMapping("listByKeyWord1")
public String listByKeyWord1(ModelMap model, OyUser user) {
//创建CriteriaBuilder安全查询工厂
//CriteriaBuilder是一个工厂对象,安全查询的开始.用于构建JPA安全查询.
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
//创建CriteriaQuery安全查询主语句
//CriteriaQuery对象必须在实体类型或嵌入式类型上的Criteria 查询上起作用。
CriteriaQuery query = criteriaBuilder.createQuery(OyUser.class);
//Root 定义查询的From子句中能出现的类型
Root userRoot = query.from(OyUser.class);
//Predicate 过滤条件 构建where字句可能的各种条件
//这里用List存放多种查询条件,实现动态查询
List predicatesList = new ArrayList<>();
//name模糊查询 ,like语句
if (user.getName() != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.like(
userRoot.get("name"), "%" + user.getName() + "%")));
}
//account模糊查询 ,like语句
if (user.getAccount() != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.like(
userRoot.get("account"), "%" + user.getAccount() + "%")));
}
// itemPrice 小于等于 <= 语句
if (user.getAge() != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.le(
userRoot.get("age"), user.getAge())));
}
//itemStock 大于等于 >= 语句 criteriaBuilder.ge
//where()拼接查询条件
query.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
TypedQuery typedQuery = entityManager.createQuery(query);
//查询
List userList = typedQuery.getResultList();
model.put("users", userList);
return "user";
}
mysql
mysql-connector-java
5.1.29
org.springframework.boot
spring-boot-starter-data-jpa
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/ouyangblog?autoReconnect=true&autoReconnectForPools=true&useUnicode=true&characterEncoding=utf8
username: ouyangcheng
password: 123456
driver-class-name: com.mysql.jdbc.Driver
druid:
initialSize: 1
minIdle: 1
maxActive: 50
maxWait: 6000
timeBetweenEvictionRunsMillis: 6000
minEvictableIdleTimeMillis: 30000
testWhileIdle: true
testOnBorrow: true
testOnReturn: true
validationQuery: SELECT 1 from dual
connectionProperties: config.decrypt=false # database connection plain password
/**
* @author oyc
* @Title: OuYangUserRepositoryTest
* @ProjectName ouyangblog
* @Description: TODO
* @date 2018/11/15 21:48
*/
@Repository
public interface OuYangUserRepository extends JpaRepository {
OuYangUser findByAccount(String account);
}
package cn.com.ouyangblog.web.rest;
import cn.com.ouyangblog.domain.OuYangUser;
import cn.com.ouyangblog.repository.OuYangUserRepository;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @author oyc
* @Title: OuYangUserController
* @ProjectName ouyangblog
* @Description: TODO
* @date 2018/11/15 21:41
*/
@Api(value = "用户模块")
@Controller
@RequestMapping("/user")
public class OuYangUserController {
@Resource
private OuYangUserRepository ouYangUserRepository;
@ApiOperation(value = "获取用户列表")
@RequestMapping(value = "/list", method = {RequestMethod.GET, RequestMethod.POST})
public String list(HttpServletRequest request, HttpServletResponse response, Model model) {
List userList = ouYangUserRepository.findAll();
model.addAttribute("userList", userList);
return "pages/userList";
}
@ApiOperation(value = "添加用户")
@PostMapping("/adduser")
public String addUser(OuYangUser bean,Model model) throws Exception {
try {
ouYangUserRepository.saveAndFlush(bean);
} catch (Exception e) {
e.printStackTrace();
}
List userList = ouYangUserRepository.findAll();
model.addAttribute("userList", userList);
return "pages/userList";
}
@ApiOperation(value = "删除用户")
@PostMapping("/deluser")
public ResponseEntity delUser(Integer id) throws Exception {
try {
ouYangUserRepository.deleteById(id);
return ResponseEntity.ok(true);
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.ok(false);
}
}
}
参考:https://www.cnblogs.com/rulian/p/6434631.html