JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体
Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。
API用来操作实体对象,执行CRUD操作,框架在后台替代我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。
二、JPA的优势
标准化
JPA 是 JCP 组织发布的 Java EE 标准之一,因此任何声称符合 JPA 标准的框架都遵循同样的架构,提供相同的访问
容器级特性的支持
JPA框架中支持大数据集、
简单方便
JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下创建实体和创建Java 类一样简单,没有任何的约束和限制,只需要使用 javax.persistence.Entity进行注释,JPA的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,开发者可以很容易地掌握。JPA基于非侵入式原则设计,因此可以很容易地和其它框架或者容器集成。
查询能力
JPA的查询语言是
高级特性
JPA 中能够支持
三、SpringData JPA
SpringData JPA是Spring提供的一套简化JPA开发的框架,按照约定好的【方法命名规则】,就可以在不写接口实现的情况下,实现对数据库的访问和操作。提供了很多CRUD功能以及分页、排序、复杂查询等。
SpringData JPA可以理解为JPA规范的再次封装,底层默认才用的是Hibernate的JPA技术实现。
四、JPA方法命名规则
# | 关键词 | 示例 | 同功能SQL |
---|---|---|---|
1 | And | findByLastnameAndFirstname | where x.lastname = ? and x.firstname = ? |
2 | Or | findByLastnameOrFirstname | where x.lastname = ? or x.firstname = ? |
3 | Is,Equals | findByFirstname,findByFirstnameEquals | where x.firstname = ? |
4 | Between | findByStartDateBetween | where x.startDate between ? and ? |
5 | LessThan | findByAgeLessThan | where x.age < ? |
6 | LessThanEquals | findByAgeLessThanEquals | where x.age <= ? |
7 | GreaterThan | findByAgeGreaterThan | where x.age > ? |
8 | GreaterThanEquals | findByAgeGreaterThanEquals | where x.age >= ? |
9 | After | findByIdAfter | where x.Id > ? |
10 | Before | findByIdBefore | where x.Id < ? |
11 | IsNull | findByNameIsNull | where x.name is null |
12 | IsNotNull,NotNull | findByNameIsNotNull,findByNameNotNull | where x.name not null |
13 | Like | findByNameLike | where x.name like ? |
14 | NotLike | findByNameNotLike | where x.name not like ? |
15 | StartingWith | findByNameStartingWith | where x.name like ? |
16 | EndingWith | findByNameEndingWith | where x.name like ? |
17 | Containing | findByNameContaining | where x.name like ? |
18 | OrderBy | findByAgeOrderByNameDesc | where x.age = ? order by name desc |
19 | Not | findByNameNot | where x.name <> ? |
20 | In | findByAgeIn(Collection<Age> ages) | where x.age in ? |
21 | NotIn | findByAgeNotIn(Collection<Age> ages) | where x.age not in ? |
22 | True | findByActiveTrue | where x.active = true |
23 | False | findByActiveFalse | where x.active = false |
24 | IgnoreCase | findByNameIgnoreCase | where UPPER(x.name) = UPPER(?) |
组合查询示例:
在UserRepository接口中findByAgeOrderByNameDesc(Integer age); 首先findByAge查询年龄=age,再通过OrderBy排序,排序条件为Name降序,生成的SQL语句即为:SELECT * FROM User WHERE Age = ? ORDER BY Name DESC
五、JPA注解
注解 解释
注解 | 解释 |
---|---|
@Entity | 声明类为实体或表 |
@Table | 声明表名 |
@Basic | 指定非约束明确的各个字段 |
@Embedded | 指定类或它的值是一个可嵌入的类的实例的实体的属性 |
@Id | 指定的类的属性,用于识别(一个表中的主键) |
@GeneratedValue | 指定如何标识属性可以被初始化,例如自动、手动、或从序列表中获得的值 |
@Transient | 指定的属性,它是不持久的,即:该值永远不会存储在数据库中 |
@Column | 指定持久属性栏属性 |
@SequenceGenerator | 指定在@GeneratedValue注解中指定的属性的值。它创建了一个序列 |
@TableGenerator | 指定在@GeneratedValue批注指定属性的值发生器。它创造了值生成的表 |
@AccessType | 这种类型的注释用于设置访问类型。如果设置@AccessType(FIELD),则可以直接访问变量并且不需要getter和setter,但必须为public。如果设置@AccessType(PROPERTY),通过getter和setter方法访问Entity的变量 |
@JoinColumn | 指定一个实体组织或实体的集合。这是用在多对一和一对多关联 |
@UniqueConstraint | 指定的字段和用于主要或辅助表的唯一约束 |
@ColumnResult | 参考使用select子句的SQL查询中的列名 |
@ManyToMany | 定义了连接表之间的多对多一对多的关系 |
@ManyToOne | 定义了连接表之间的多对一的关系 |
@OneToMany | 定义了连接表之间存在一个一对多的关系 |
@OneToOne | 定义了连接表之间有一个一对一的关系 |
@NamedQueries | 指定命名查询的列表 |
@NamedQuery | 指定使用静态名称的查询 |
1、pom.xml 添加依赖
<!-- spring jpa --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> <scope>provided</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
2、创建实体表
package com.demo.springboot.entity; ? import lombok.Data; import javax.persistence.*; ? @Data @Entity //告诉JPA这是一个实体类(和数据表映射的类) @Table(name = "t_user") //@Table来指定和哪个数据表对应;如果省略默认表名就是user; public class User { @Id //这是一个主键 @GeneratedValue(strategy = GenerationType.IDENTITY) //自增主键 private Integer id; ? @Column(name = "last_name", length = 50) //这是和数据表对应的一个列 private String lastName; ? @Column //省略默认列名就是属性名 private String email; }
3、创建UserRepository
package com.demo.springboot.repository; ? import com.demo.springboot.entity.User; import org.springframework.data.jpa.repository.JpaRepository; ? /** * 继承JpaRepository来完成对数据库的操作 * JpaRepository 继承了CrudRepository、PagingAndSortingRepository、QueryByExampleExecutor * 实现了常用的增删改查、分页、排序等功能 */ public interface UserRepository extends JpaRepository<User, Integer> { User findByLastName(String lastName); // 根据JPA命名规则,不需要实现即可使用 ? User findByEmail(String email); }
4、创建UserController
package com.demo.springboot.controller; ? import com.demo.springboot.entity.User; import com.demo.springboot.repository.UserRepository; 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.PostMapping; import org.springframework.web.bind.annotation.RestController; ? @RestController public class UserController { ? @Autowired UserRepository userRepository; @PostMapping("/user") public User insertUser(User user) { // 使用save方法进行新增 User save = userRepository.save(user); return save; } @GetMapping("/user/id/{id}") public User getUser(@PathVariable("id") Integer id) { User user = userRepository.findOne(id); return user; } ? @GetMapping("/user/name/{lastName}") public User getUserByLastName(@PathVariable("lastName") String lastName) { // 调用自定义的findByLastName接口,不需要自己实现 User user = userRepository.findByLastName(lastName); return user; } ? @GetMapping("/user/email/{email}") public User getUserByEmail(@PathVariable("email") String email) { User user = userRepository.findByEmail(email); return user; } }
访问接口时,控制台打印出来的SQL依次为:
Hibernate: insert into t_user (email, last_name) values (?, ?)
Hibernate: select user0_.id as id1_0_0_, user0_.email as email2_0_0_, user0_.last_name as last_nam3_0_0_ from t_user user0_ where user0_.id=?
2021-09-05 10:17:29.955 INFO 11692 --- [nio-8080-exec-8] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select user0_.id as id1_0_, user0_.email as email2_0_, user0_.last_name as last_nam3_0_ from t_user user0_ where user0_.last_name=?
Hibernate: select user0_.id as id1_0_, user0_.email as email2_0_, user0_.last_name as last_nam3_0_ from t_user user0_ where user0_.email=?
七、参考文档
https://baike.baidu.com/item/JPA/5660672?fr=aladdin
https://blog.csdn.net/wujiaqi0921/article/details/78789087