一、JPA概述
JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。
二、JPA的优点
1,标准化JPA是JCP组织发布的Java EE标准之一,因此任何声称符合JPA标准的框架都遵循同样的架构,提供相同的访问API,这保证了基于JPA开发的企业应用能够经过少量的修改就能够在不同的JPA框架下运行。
2,容器级特性的支持JPA框架中支持大数据集、事务、并发等容器级事务,这使得 JPA 超越了简单持久化框架的局限,在企业应用发挥更大的作用。
3,简单方便JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下创建实体和创建Java类一样简单,没有任何的约束和限制,只需要使用javax.persistence.Entity进行注释,JPA的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,开发者可以很容易地掌握。JPA基于非侵入式原则设计,因此可以很容易地和其它框架或者容器集成。
4,查询能力 JPA的查询语言是面向对象而非面向数据库的,它以面向对象的自然语法构造查询语句,可以看成是Hibernate HQL的等价物。JPA定义了独特的JPQL(Java Persistence Query Language),JPQL是EJB QL的一种扩展,它是针对实体的一种查询语言,操作对象是实体,而不是关系数据库的表,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。
5,高级特性 JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,这样的支持能够让开发者最大限度的使用面向对象的模型设计企业应用,而不需要自行处理这些特性在关系数据库的持久化。
三、使用JPA
第一步:导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.springboot</groupId>
<artifactId>zhouxs</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zhouxs</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--添加JDBC依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
第二步: 编写实体类
package com.springboot.zhouxs.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)//自动生成主键
@Column
private Integer id;
@Column
private String username;
@Column
private String password;
}
第三步:编写dao层接口
package com.springboot.zhouxs.dao;
import com.springboot.zhouxs.pojo.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User,Integer> {
/**
* JpaRepository<User,Integer>第一个参数为实体类,第二个参数为你的主键类型
*/
}
第四步: application.properties配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql:///db_jpa?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=19990704
#如果不等于update的话,每次运行程序都会创建一次表
spring.jpa.hibernate.ddl-auto=update
#控制台显示sql
spring.jpa.show-sql=true
第五步: Jnuit测试
package com.springboot.zhouxs;
import com.springboot.zhouxs.dao.UserRepository;
import com.springboot.zhouxs.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class ZhouxsApplicationTests {
@Autowired
UserRepository userRepository;
@Test
void contextLoads() {
//查询全部数据
List<User> all = userRepository.findAll();
System.out.println(all);
}
}
运行结果:[User(id=1, username=张三, password=666666), User(id=2, username=李四, password=666666)]
四、jpa常用的核心接口
在Spring Boot中通过了如下核心接口用于我们做增删改查(crud).
Repository、CrudRepository、PagingAndSortingRepository、JpaRepository、JPASpecificationExecutor.
4.1、Repository接口
Repository是SpringBoot的核心接口,接受要管理的类以及id的类型作为参数,主要用来做标识接口,捕获使用的类型用来扩展此接口,该接口提供了方法名称命名查询方式和基于@Query注解查询与更新
package cn.zhou.springboot_jpa.dao;
import cn.zhou.springboot_jpa.pojo.User;
import org.springframework.data.repository.Repository;
import java.util.List;
public interface UserRepository extends Repository<User,Integer> {
//方法使用驼峰命名
//根据姓名查询
List<User> findByUsername(String name);
//根据id查询
List<User> findById(Integer id);
//根据id和姓名查询
List<User> findByIdAndUsername(Integer id,String username);
}
测试
@Autowired
UserRepository userRepository;
/**
* 根据姓名查询
*/
@Test
void findByUsername() {
List<User> ss = this.userRepository.findByUsername("李四");
for (User s : ss) {
System.out.println(s);
}
}
/**
* 根据id查询
*/
@Test
void findUserById(){
List<User> byId = this.userRepository.findById(3);
for (User user : byId) {
System.out.println(user);
}
}
/**
* 根据用户名和id查询用户所有信息
*/
@Test
void findByIdAndUsername () {
List<User> ss = this.userRepository.findByIdAndUsername(2, "李四");
for (User s : ss) {
System.out.println(s);
}
}
基于@Query查询、更新
package cn.zhou.springboot_jpa.dao;
import cn.zhou.springboot_jpa.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UsersRepositoryQuery extends JpaRepository<User,Integer> {
//根据姓名查询所有用户信息
@Query(value = "select * from user where username =?",nativeQuery=true )
List<User> findAllByUsername(@Param("username") String username);
//根据id删除
@Modifying
@Query(value = "delete from user where id=?1",nativeQuery = true)
@Override
void deleteById(Integer id);
}
测试
@Autowired
UsersRepositoryQuery usersRepositoryQuery;
/**
* 根据姓名查询所有用户信息
*/
@Test
void findAllByUsername () {
List<User> allByUsername = this.usersRepositoryQuery.findAllByUsername("李四");
for (User user : allByUsername) {
System.out.println(user);
}
}
/**
* 根据id删除
*/
@Test
void deleteUser () {
this.usersRepositoryQuery.deleteById(2);
System.out.println("删除成功!");
}
4.2、CrudRepository接口
CrudRepository继承了是Repository的子类,主要用来做简单的增删改查.
package cn.zhou.springboot_jpa.dao;
import cn.zhou.springboot_jpa.pojo.User;
import org.springframework.data.repository.CrudRepository;
public interface UserCrudRepository extends CrudRepository<User,Integer> {
}
测试
@Autowired
UserCrudRepository userCrudRepository;
/**
* 添加用户
*/
@Test
void addUser () {
User user = new User();
user.setUsername("asdaa");
user.setPassword("444444");
User save = userCrudRepository.save(user);
System.out.println(save!=null?"添加成功":"添加失败");
}
/**
* 查询用户
*/
@Test
void findUser(){
Iterable<User> all = userCrudRepository.findAll();
for (User user : all) {
System.out.println(user);
}
}
4.3、PagingAndSortingRepository接口
PagingAndSortingRepository接口是CrudRepository接口的子类,主要用来排序和分页.
package cn.zhou.springboot_jpa.dao;
import cn.zhou.springboot_jpa.pojo.User;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface UserSortingRepository extends PagingAndSortingRepository<User,Integer> {
}
测试
/**
* 排序查询
*/
@Autowired
UserSortingRepository userSortingRepository;
@Test
void sortUser () {
//Sort对象封装了排序规则
Iterable<User> all = userSortingRepository.findAll(Sort.by(Sort.Direction.DESC, "id"));
for (User user : all) {
System.out.println(user);
}
}
/**
* 分页查询
*/
@Test
void pageUser () {
PageRequest of = PageRequest.of(1, 2);
Page<User> all = userSortingRepository.findAll(of);
System.out.println("总条数:"+all.getTotalElements());
System.out.println("多少页:"+all.getTotalPages());
for (User user : all) {
System.out.println(user);
}
}
/**
* 分页+查询
*/
@Test
void userPageAndSort () {
Sort sort = Sort.by(Sort.Direction.DESC);
PageRequest of = PageRequest.of(1, 2, sort);
Page<User> all = userSortingRepository.findAll(of);
System.out.println("总条数:"+all.getTotalElements());
System.out.println("多少页:"+all.getTotalPages());
for (User user : all) {
System.out.println(user);
}
}
4.4、JpaRepository接口
JpaRepository接口是PagingAndSortingRepository接口的子类,主要用来对继承的父接口中方法的返回值进行适配.
public interface UsersRepository extends JpaRepository<Users,Integer> {
}
测试
@Test
public void UserJpaRepositorySort() {
//Order 定义了排序规则
Sort.Order order=new Sort.Order(Sort.Direction.DESC,"id");
//Sort对象封装了排序规则
Sort sort=new Sort(order);
List<Users> list= this.usersRepository.findAll(sort);
for (Users users:list){
System.out.println(users);
}
}
4.5、JPASpecificationExecutor接口
JPASpecificationExecutor接口是独立的接口,主要用来多条件查询以及可以进行分页和排序.
package cn.zhou.springboot_jpa.dao;
import cn.zhou.springboot_jpa.pojo.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface UserJpaSpecificationExecutor extends JpaRepository<User,Integer>, JpaSpecificationExecutor<User> {
}
测试
//多条件查询
@Autowired
UserJpaSpecificationExecutor userJfe;
@Test
void testDtj1 () {
Specification<User> specification = new Specification<User>() {
/**
*
* @param root 对象查询封装的属性
* @param criteriaQuery 封装了查询部分的各个信息
* @param criteriaBuilder 查询条件构造器
* @return
*/
@Override
public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
List<Predicate> list = new ArrayList<>();
//第一个参数
list.add(criteriaBuilder.equal(root.get("username"),"张三"));
//第二个参数
list.add(criteriaBuilder.equal(root.get("password"),"666666"));
//把参数存到对象数组
Predicate[] predicates = new Predicate[list.size()];
//返回转换后的集合
return criteriaBuilder.and(list.toArray(predicates));
}
};
//排序对象
Sort sort = Sort.by(Sort.Direction.DESC, "id");
//分页对象,当前页默认为0
Pageable pageable = PageRequest.of(0,2,sort);
Page<User> all = userJfe.findAll(specification, pageable);
for (User user : all) {
System.out.println(user);
}
}