本文主要介绍 JPA 的实际使用,相关的环境及软件信息如下:JPA 2.2(eclipselink 2.7.10、hibernate-entitymanager 5.6.10.Final、openjpa 3.2.2),JPA 3.0(eclipselink 3.0.2、hibernate-core-jakarta 5.6.10.Final)。
1、JPA 2.2 使用
工程目录结构如下:

1.1、引入依赖
这里使用 eclipselink 作为 JPA 的实现框架。- <dependency>
- <groupId>org.eclipse.persistence</groupId>
- <artifactId>org.eclipse.persistence.jpa</artifactId>
- <version>2.7.10</version>
- </dependency>
复制代码 其他的依赖可自行引入,如数据库驱动、lombok 等。
1.2、创建实体类
1.2.1、Student.java
- package com.abc.demojpa.entity;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import org.hibernate.annotations.CreationTimestamp;
- import org.hibernate.annotations.UpdateTimestamp;
- import javax.persistence.*;
- import java.time.LocalDateTime;
- @NoArgsConstructor
- @AllArgsConstructor
- @Data
- @Entity
- @Table(name = "a_student")
- @NamedQuery(name = "queryAll", query = "select s from Student s")
- public class Student {
- @Id
- @GeneratedValue
- private Long id;
- @Column(name = "create_time")
- private LocalDateTime createTime;
- @Column(name = "modify_time")
- private LocalDateTime modifyTime;
- private String name;
- private Integer age;
- @Column(name = "home_address")
- private String homeAddress;
- }
复制代码 1.2.2、BaseEntity.java
- package com.abc.demojpa.entity;
- import lombok.Data;
- import javax.persistence.Column;
- import javax.persistence.GeneratedValue;
- import javax.persistence.Id;
- import javax.persistence.MappedSuperclass;
- import java.time.LocalDateTime;
- @Data
- //该类的属性都将映射到其子类的数据库字段中
- @MappedSuperclass
- public class BaseEntity {
- @Id
- @GeneratedValue
- private Long id;
- @Column(name = "create_time")
- private LocalDateTime createTime;
- }
复制代码 1.2.3、Teacher.java
Teacher 继承了 BaseEntity,主要为了测试属性的继承。- package com.abc.demojpa.entity;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import javax.persistence.*;
- @NoArgsConstructor
- @Data
- @Entity
- @Table(name = "a_teacher")
- public class Teacher extends BaseEntity {
- private String name;
- private Integer age;
- }
复制代码 1.3、编写 JPA 配置文件 (persistence.xml)
该配置文件需放在 META-INF 目录下。- <?xml version="1.0" encoding="UTF-8"?>
- <persistence version="2.2"
- xmlns="http://xmlns.jcp.org/xml/ns/persistence"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
- <persistence-unit name="myUnit">
- <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
- <class>com.abc.demojpa.entity.Student</class>
- <class>com.abc.demojpa.entity.Teacher</class>
- <properties>
- <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
- <property name="javax.persistence.jdbc.url" value="jdbc:mysql://10.49.196.10:3306/test?useUnicode=true&characterEncoding=UTF-8"/>
- <property name="javax.persistence.jdbc.user" value="root"/>
- <property name="javax.persistence.jdbc.password" value="123456"/>
- <property name="eclipselink.logging.level" value="INFO" />
- <property name="eclipselink.ddl-generation" value="create-or-extend-tables" />
- </properties>
- </persistence-unit>
- </persistence>
复制代码 eclipselink 开头的配置是 eclipselink 自带的扩展配置,用于实现功能的增强;详细的扩展配置说明可参考官网说明:https://www.eclipse.org/eclipselink/documentation/2.7/jpa/extensions/toc.htm。
1.4、使用例子
1.4.1、插入实体
- @Test
- public void persist() {
- entityManager.getTransaction().begin();
- Student student = new Student();
- student.setName("小明");
- student.setCreateTime(LocalDateTime.now());
- student.setModifyTime(LocalDateTime.now());
- student.setAge(15);
- student.setHomeAddress("江苏");
- Student student2 = new Student();
- student2.setName("小红");
- student2.setAge(18);
- student2.setHomeAddress("广东");
- Teacher teacher = new Teacher();
- teacher.setCreateTime(LocalDateTime.now());
- teacher.setName("张三");
- teacher.setAge(35);
- entityManager.persist(student);
- entityManager.persist(student2);
- entityManager.persist(teacher);
- entityManager.getTransaction().commit();
- }
复制代码 1.4.2、查询实体
- @Test
- public void find() {
- Student student = entityManager.find(Student.class, 1501L);
- logger.info("student={}", student);
- }
复制代码 1.4.3、更新实体(先查再更新)
- @Test
- public void modify() {
- entityManager.getTransaction().begin();
- Student student = entityManager.find(Student.class, 1501L);
- student.setName("小明2");
- entityManager.getTransaction().commit();
- }
复制代码 1.4.4、更新实体(直接根据id更新)
- @Test
- public void merge() {
- entityManager.getTransaction().begin();
- Student student = new Student();
- student.setId(1501L);
- student.setName("小明3");
- student.setAge(16);
- entityManager.merge(student);
- entityManager.getTransaction().commit();
- }
复制代码 1.4.5、删除实体
- @Test
- public void remove() {
- entityManager.getTransaction().begin();
- Student student = entityManager.find(Student.class, 1501L);
- entityManager.remove(student);
- entityManager.getTransaction().commit();
- }
复制代码 1.4.6、JPQL 查询
- @Test
- public void select() {
- //查询一个字段
- Query query = entityManager.createQuery("select s.name from Student s where s.age>10", String.class);
- List<String> result = query.getResultList();
- logger.info("result={}", result);
- //查询多个字段 (?n 占位符:传统 ? 占位符的改良占位符,仅仅适应 JPQL 查询)
- query = entityManager.createQuery("select s.name,s.homeAddress from Student s where s.age>?1 and s.name like ?2", Object[].class);
- query.setParameter(1, 10);
- query.setParameter(2, "%小%");
- List<Object[]> result2 = query.getResultList();
- for (Object[] arr : result2) {
- String s = "";
- for (Object o : arr) {
- s += o.toString() + ",";
- }
- logger.info(s);
- }
- //查询对象 (:name 占位符:变量名形式的占位符,仅仅适应 JPQL 查询)
- query = entityManager.createQuery("select s.name,s.homeAddress from Student s where s.age between :min and :max and s.name like '%小%' order by s.id", Student.class);
- query.setParameter("min", 10);
- query.setParameter("max", 40);
- //设置结果的开始位置,最大记录条数,可用来实现分页
- query.setFirstResult(0);
- query.setMaxResults(10);
- List<Student> result3 = query.getResultList();
- logger.info("result3={}", result3);
- //聚合操作
- query = entityManager.createQuery("select max(s.age) from Student s");
- Object result4 = query.getSingleResult();
- logger.info("result4={}", result4);
- //对应Student实体类中定义的静态查询”queryAll“
- query = entityManager.createNamedQuery("queryAll");
- List<Student> result5 = query.getResultList();
- logger.info("result5={}", result5);
- }
复制代码 1.4.7、JPQL 更新
- @Test
- public void update() {
- entityManager.getTransaction().begin();
- Query query = entityManager.createQuery( "update Student SET age=16 where name='小明'");
- query.executeUpdate();
- entityManager.getTransaction().commit();
- }
复制代码 1.4.8、JPQL 删除
- @Test
- public void delete() {
- entityManager.getTransaction().begin();
- Query query = entityManager.createQuery( "delete from Student where id=1501");
- query.executeUpdate();
- entityManager.getTransaction().commit();
- }
复制代码 1.4.9、JPQL 本地查询,直接 SQL 语句查询数据
- @Test
- public void nativeSelect() {
- Query query = entityManager.createNativeQuery("select s.* from a_student s where s.age>?", Student.class);
- query.setParameter(1, 10);
- List<Student> result = query.getResultList();
- logger.info("result={}", result);
- }
复制代码 1.4.10、JPA 标准 API 使用一
类似 SQL:select name from student where name='小明'- @Test
- public void criteria() {
- CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
- CriteriaQuery<String> criteriaQuery = criteriaBuilder.createQuery(String.class);
- Root<Student> root = criteriaQuery.from(Student.class);
- criteriaQuery.select(root.get("name"));
- criteriaQuery.where(criteriaBuilder.equal(root.get("name"), "小明"));
- TypedQuery<String> query = entityManager.createQuery(criteriaQuery);
- List<String> list = query.getResultList();
- logger.info(list.toString());
- }
复制代码 1.4.11、JPA 标准 API 使用二
类似 SQL:select id,name,age from student where age>=10 order by age,name desc- @Test
- public void criteria2() {
- CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
- CriteriaQuery<Student> criteriaQuery = criteriaBuilder.createQuery(Student.class);
- Root<Student> root = criteriaQuery.from(Student.class);
- //Student 实体类需要有对应的构造方法
- criteriaQuery.multiselect(root.get("id"), root.get("name"), root.get("age"), root.get("homeAddress"));
- criteriaQuery.where(criteriaBuilder.ge(root.get("age"), 10));
- criteriaQuery.orderBy(criteriaBuilder.asc(root.get("age"))).orderBy(criteriaBuilder.desc(root.get("name")));
- TypedQuery<Student> query = entityManager.createQuery(criteriaQuery);
- List<Student> list = query.getResultList();
- logger.info(list.toString());
- }
复制代码 1.4.12、JPA 标准 API 使用三
类似 SQL:select age,count(*) from student group by age having age=10 order by age,name desc */ @Test public void criteria2() { CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Student.class); Root root = criteriaQuery.from(Student.class); //Student 实体类需要有对应的构造方法 criteriaQuery.multiselect(root.get("id"), root.get("name"), root.get("age"), root.get("homeAddress")); criteriaQuery.where(criteriaBuilder.ge(root.get("age"), 10)); criteriaQuery.orderBy(criteriaBuilder.asc(root.get("age"))).orderBy(criteriaBuilder.desc(root.get("name"))); TypedQuery query = entityManager.createQuery(criteriaQuery); List list = query.getResultList(); logger.info(list.toString()); } /** * Criteria API * select age,count(*) from student group by age having age |