最近通过源码的方式尝试去快速入门一个技术,虽然效率不快,但掌握的很牢固
一、JPA简介
JPA(Java Persistence API)java持久层api,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。Sun引入新的JPA ORM规范出于两个原因:其一,简化现有JavaEE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。
二、spring data jpa的使用
2.1 安装
2.1.1 pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.0</version>
</dependency>
2.1.2 配置文件
########## jpa ###########
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/besteamcloud?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT
spring.datasource.username=root
spring.datasource.password=123123
2.1.3 repository搭建
entity:
package org.besteam.learnjpa.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.util.Date;
/**
* @author ginwu
* @date 2019/4/24 16:06
* @description
*/
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String deptName;
private String parentName;
private Integer sort;
private Date createTime;
}
repository:
package org.besteam.learnjpa.repository;
import org.besteam.learnjpa.entity.Dept;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @author ginwu
* @date 2019/4/24 16:12
* @description
*/
public interface DeptRepository extends JpaRepository<Dept,Long> {
}
此时项目即可正常启动。
三、spring-data-jpa中的repository
上面的那些都是Spring Data为了兼容NoSQL而进行的一些抽象封装,从JpaRepository开始是对关系型数据库进行抽象封装。从上图可以看出JpaRepository中的方法都是来自SimpleJpaRepository类,如果想深入了解可源码进行追踪学习。
3.1 JpaRepository中的方法
如果想了解源码,也可以对源码进行追踪学习。此处只对方法和用法进行说明
3.2 JpaRepository中方法的使用
package org.besteam.learnjpa.controller;
import org.besteam.learnjpa.entity.Dept;
import org.besteam.learnjpa.repository.DeptRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
import java.util.List;
/**
* @author ginwu
* @date 2019/4/24 16:03
* @description
**/
@RestController
@RequestMapping("/api")
public class BtController {
@Autowired
private DeptRepository deptRepository;
@GetMapping("/info/{id}")
public Dept getInfo(@PathVariable Long id){
return deptRepository.findById(id).get();
}
@GetMapping("/save")
public String saveInfo(){
Dept d = new Dept();
d.setDeptName("测试部门");
d.setCreateTime(new Date());
d.setParentName("BT官方开发部门");
deptRepository.save(d);
return "ok";
}
@GetMapping("all")
public List<Dept> getAll(){
return (List<Dept>) deptRepository.findAll();
}
}
四、自定义查询方法
4.1简介
spring jpa repository的原理采用动态代理机制。这里有两种查询方式,一种是通过方法名称指定查询关键字和条件,另一种是通过注解来手动定义查询语句。两种查询方法更具实际的使用情况选择。
/**
* 根据方法名称中的条件和关键字查询
*/
@GetMapping("/findDeptName/{name}")
public Dept findName(@PathVariable String name){
//通过name查询
return deptRepository.findByDeptName(name);
}
4.2 方法名创建查询
4.2.1关键字简介(部分)
And关键字
deptRepository.findByDeptNameAndParentName(name,parentName);
Or关键字
deptRepository.findByDeptNameOrParentName(name,parentName);
In关键字
deptRepository.findByDeptNameIn(List names);
LessThan关键字(<)
deptRepository.findByIdLessThan(Id);
LessThanEquals关键字(<=)
deptRepository.findByIdLessThanEquals(Id);
GreaterThan关键字(>)
deptRepository.findByIdGreaterThan(Id);
GreaterThanEquals关键字(>=)
deptRepository.findByIdGreaterThanEquals(Id);
OrderBy关键字
deptRepository.findByDeptNameOrderByIdDesc(name);
4.2.2 分页查询
由上图可以看出findAll中需要一个传递分页参数的实例,返回的是分页Page实体。
Pageable
进入Pageable中我们发现只是一个接口并不能设置一些参数,进入他的实现类中去找,
发现可以通过PageRequest中的of静态方法进行分页参数配置。
@GetMapping("/page/{current}")
public Page<Dept> getPage(@PathVariable Integer current){
return deptRepository.findAll(PageRequest.of(current,2));
}
4.3 注解手动创建查询
4.3.1 @Query简介
使用示例:
public interface DeptRepository extends JpaRepository<Dept,Long> {
Dept findByDeptName(String name);
Dept findByDeptNameAndParentName(String name, String parentName);
@Query(value = "select d from Dept d")
List<Dept> selectAll();
@Query(value = "select d from Dept d where d.deptName = ?1")
List<Dept> selectName(String name);
@Query(value = "select * from dept where dept_name = ?1 and parent_name = ?2",nativeQuery = true)
List<Dept> selectNameAndParent(String name, String parentName);
}
4.3.2 Query的排序、分页
@GetMapping("/page/{current}")
public Page<Dept> selectPage(@PathVariable Integer current){
return deptRepository.selectPage(PageRequest.of(current,2,new Sort(Sort.Direction.DESC,"id")));
}
@Query(value = "select d from Dept d")
Page<Dept> selectPage(Pageable pageable);
Sort排序
从上面的PageRequest源码图片中可以看到of重载方法中有一个Sort参数,
从上图可以看出创建sort有两种途径,一种是通过构造方法,另一种是通过静态方法。其中direction选择排序方式,properties排序属性。
即:
@GetMapping("/page/{current}")
public Page<Dept> selectPage(@PathVariable Integer current){
// deptRepository.selectPage(PageRequest.of(current,2,new Sort(Sort.Direction.DESC,"id")));
return deptRepository.selectPage(PageRequest.of(current,2,Sort.by(Sort.Direction.DESC,"id")));
}