JPA

介绍

JPA(Java Persistence API),是Java EE 5的标准ORM接口,也是ejb3规范的一部分

spring中使用时的配置

配置文件:application.properties

  1. spring.datasource.username = <用户名>
  2. spring.datasource.password = <密码>
  3. spring.datasource.url=jdbc:mysql://localhost:3306/<数据库名>
  4. # 每次新启动项目时操作数据库的方式,可选值有:
  5. # none:不操作
  6. # create:新建表,如果已存在则清空数据
  7. # create-drop:退出时删除表
  8. # update:更新表,没有表会创建,已有数据不会清空。软更改表结构不会更新,比如新增约束、更改值是否可以为空
  9. # validate:校验模型与数据库的字段是否相同,不同则报错
  10. # 网友建议:不要使用create和create-drop
  11. spring.jpa.hibernate.ddl-auto=update
  12. # 数据库操作时显示SQL语句
  13. spring.jpa.show-sql=true
  14. # 解决 Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set 报错
  15. # 设置默认引擎为InnoDB
  16. spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

注解

@Entity


介绍

表明这个Class是实体类,并且使用默认的ORM规则,即class名对应数据库中的表名,class字段名即表中的列名

作用对象

Class

参数

@Table


介绍

Table用来定义entity主表的name,catalog,schema等属性

作用对象

Class

参数

  • name:表名
  • catalog:对应关系数据库中的catalog
  • schema:对应关系数据库中的schema
  • UniqueConstraints:定义一个UniqueConstraints数组,指定需要建唯一约束的列,在抽象父类上使用此方法无效。

    使用方法

    // 设置表名、创建唯一约束
    // 定义多个唯一性约束时,使用{}包括所有的@UniqueConstraint内容
    // 在多个字段上创建唯一性约束时,columnNames参数指定多个值,这些值使用{}包括
    @Table(name = "student", uniqueConstraints=@UniqueConstraint(name = "UK_work_num",         columnNames="work_num"))
    public class StudentUser extends User{
    }
    

    @Id


介绍

声明当前field为映射表中的主键列

作用对象

fieldmethod

设置联合主键的方法

JPA需要定义一个特殊的ID类,该类使用@IdClass注释附加到实体类

package com.example.eduadministration.Model;

import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.io.Serializable;

/**
 * @author 秋猫
 * @version 2021-05-25 12:03
 * @description 成绩表,学生选完课没有成绩时成绩字段为NULL
 */
@Entity
@Data
@NoArgsConstructor
@Table(name = "grade")
@IdClass(PrimaryKey.class)
public class Grade {

    /**
     * 学生学号
     */
    @Id
    @Column(length = 20)
    private String studentId;

    /**
     * 课程代码
     */
    @Id
    @Column(length = 20)
    private String courseId;

    /**
     * 分数
     */
    @Column(precision = 5, scale = 1)
    private double score;
}

/**
 * 主键类,用于定义实体类的主键
 */
class PrimaryKey implements Serializable {

    String studentId;

    String courseId;
}

@GeneratedValue


介绍

定义主键的生成策略

作用对象

fieldmethod

参数

  • strategy :生成策略。默认值:GenerationType.AUTO
  • generator :生成器。默认值: ""

    @Query


介绍

作用对象

methodannotation_type

参数

  • value :要执行的语句。默认空
  • countQuery
  • countProjection
  • nativeQuery :True表示执行原生SQL语句,默认为False,False代表使用JPQL
  • name
  • countName

    使用方法

    //为 @Query 注解传递参数的方式1: 命名参数的方式. 冒号后面的表示参数
    @Query("SELECT p FROM Person p WHERE p.lastName = :lastName AND p.email = :email")
    List<Person> testQueryAnnotationParams2(@Param("email") String email, @Param("lastName") String lastName);
    

    @Column


介绍

设置类属性映射的数据库表列,比如列名

作用对象

methodfield

参数

  • name :指定映射的表列名,默认””
  • unique :是否设置唯一性约束,约束名为前缀UK_后面随机生成,默认false
  • nullable :是否可以为空,默认true
  • columnDefinition :创建表时,该字段创建的SQL语句,一般用于使用Entity生成表时使用
  • length:最大长度
  • precision :字段类型为double时,表示数值的总长度
  • scale :字段类型为double时,表示小数点所占的位数

@Component


介绍

标记一个Spring组件,用于把普通POJO类实例化到spring容器中

作用对象

TYPE

枚举类

GenerationType

介绍

主键生成策略

枚举值

  • TABLE
  • SEQUENCE
  • IDENTITY :主键由数据库控制
  • AUTO :主键由程序控制

    注意事项

  • 设置为AUTO后,直接插入数据库会出错,提示没有给主键赋值,也就是说AUTO策略只能通过程序来控制数据库,否则将出错。

JPQL

介绍

Java Presistence Query Language(JPQL),java持久性查询语言。Java EE中,JPQL是专门为Java应用程序访问和导航实体实例设计的。它是JPA规范的重要组成部分,其实就是一种查询语言,语法类似于SQL,但与SQL有着本质的区别。

JPQL与SQL

  • JPQL是面向对象的查询语言,因此它可以完全理解继承、多态和关联等特征。而且JPQL内置了大量函数,极大地方便了JPQL查询的功能。当然JPQL底层依然是基于SQL的,但JPQL到SQL的转换无须开发者关心,JPQL解析器会负责完成这种转换,并负责执行这种转换的SQL语句来更新数据库。
  • SQL是面向关系数据库的查询语言,因此SQL操作的对象是数据表、数据列;而JQPL操作的对象是实体对象,对象属性。
  • 推荐使用JPQL,降低与数据库的耦合性。

    代码对比

    SQL:
    // 原生SQL
    SELECT name, age, user_id FROM t_user
    

    JPQL:
    // 面向对象的JPQL语句
    SELECT name, age, userId FROM User
    

    BUG

    unique失效

    案例

    @Column(name = "work_num", unique = true, nullable = false)
    private String workNum;
    

    报错信息

    Specified key was too long; max key length is 1000 bytes
    

    解释

    指定字段长度过长,无法创建唯一约束

    解决办法

    指定字段的最大长度

    @Column(name = "work_num", unique = true, nullable = false, length = 10)
    private String workNum;
    

    使用技巧

    实现联表查询以及Repository层查询结果模型转换

    首先要定义想要的结果模型,其中需要定义构造器。

    @Data
    @AllArgsConstructor
    public class StudentGrade {
    
      /**
       * 学生学号
       */
      private String studentId;
    
      /**
       * 课程代号
       */
      private int courseId;
    
      /**
       * 课程名称
       */
      private String courseName;
    
      /**
       * 课程成绩
       */
      private double score;
    
      /**
       * 学年
       */
      private String schoolYear;
    
      /**
       * 学期
       */
      private String schoolTerm;
    }
    

在Repository层接口的方法上使用@Query注解,注解的value参数设置为JPQL语句。查询的结果处使用new <结果模型>(字段)的方式将查询的结果转换成想要的模型。

  • <结果模型>需要是类的全路径
  • 冒号+参数可以使用方法中接收的参数
    @Query("SELECT new com.example.eduadministration.DAO.StudentGrade(a.studentId, b.courseId, c.name, b.score, c.schoolYear, c.schoolTerm) " +
         "FROM StudentUser AS a, CourseStudent AS b, Course AS c " +
         "WHERE a.studentId = :studentId AND b.studentId = a.studentId AND c.courseId = b.courseId")
    List<StudentGrade> fetchAllCourseByStudentId(@Param("studentId") String studentId);