前置概念:
POJO
POJO (Plain Old Java Object) 是指 普通的 Java 对象,它没有继承自特定的类,也没有实现特定的接口。POJO 是一种简单的、符合 Java Bean 规范的 Java 类。可以把它理解成一个最普通的 JavaBean。
POJO 的特点是:
- 无特定继承:POJO 不需要继承自特定的父类,通常不继承任何框架类。
- 无特定接口:POJO 不需要实现任何特定的接口。
- 属性和方法:POJO 通常拥有一组私有属性,并提供公共的 getter 和 setter 方法来访问这些属性。
- 无框架依赖:POJO 不依赖于任何特定的框架或技术(如 EJB 等)。它是一个完全独立的 Java 类。
示例代码如下:
1 | public class Person { |
在 ORM框架中,POJO类通常用作映射数据库。
——————————————————————————————————————————————————
ORM框架
ORM框架(Object-Relational Mapping Framework,面向对象与关系型数据库映射框架)是一种技术,它使得开发者能够在面向对象编程中使用对象来表示数据库中的数据,而不需要直接操作数据库中的表、行和列。ORM框架通过将对象的属性与数据库表中的字段相映射,实现了面向对象程序与关系型数据库之间的转换。
ORM的核心概念是将数据库中的表(table)、列(column)、映射到类(class)、和**对象(object)**的属性(field),使得开发者可以通过操作对象来进行数据库操作,而不必编写大量的SQL语句。ORM框架通过为开发者提供高级API,简化了数据库操作,自动生成SQL语句来完成对数据库的增、删、改、查操作。
工作原理
ORM框架通过映射关系将数据库表与程序中的类关联起来。通常包括以下几个步骤:
- 类映射:每个数据库表通常对应一个类,类的每个字段(属性)映射到表的每一列。类对象的操作会反映到数据库表的操作。
- CRUD操作:开发者通过操作对象(增、删、改、查),ORM框架会自动将这些操作转换为相应的SQL语句,并执行这些SQL语句来操作数据库。
- 映射配置:ORM框架通常需要通过注解或XML配置文件指定类与数据库表之间的映射关系。
熟知的 ORM框架包括 Mybatis-plus,Hibernate等等。
——————————————————————————————————————————————————
JPA
JPA(Java Persistence API)是一个用于 Java 平台上的对象关系映射(ORM)规范,它提供了一组标准化的接口和方法来简化 Java 应用程序与数据库之间的交互。JPA 使得 Java 开发者可以以面向对象的方式操作关系型数据库,并且与底层数据库的细节分离,避免了直接操作 SQL 语句。
JPA 本身并不是一个实现,而是一个规范。它定义了 Java 应用程序与关系型数据库交互的标准,开发者可以通过实现 JPA 规范的 ORM 框架(如 Hibernate、EclipseLink、OpenJPA)来使用 JPA 功能。
概念组成:
实体类(Entity):
- 实体类是一个 Java 类,它代表了数据库中的一张表。每个实体类的实例代表该表的一行记录。实体类通常需要通过注解(如
@Entity
)来标识,JPA 会根据这些实体类生成对应的数据库表。
持久化上下文(Persistence Context):
- 持久化上下文是 JPA 管理实体的生命周期的容器。它负责跟踪所有已持久化实体的状态,并确保数据的一致性和持久性。持久化上下文与事务紧密结合。
实体管理器(EntityManager):
- 实体管理器是 JPA 提供的一个接口,它用于管理实体对象的生命周期,执行对数据库的操作,如保存、更新、删除和查询。实体管理器是 JPA 操作数据库的核心接口。
查询语言(JPQL):
- JPA 提供了一种面向对象的查询语言,称为 JPQL(Java Persistence Query Language)。JPQL 允许开发者使用面向对象的语法来执行数据库查询,而无需直接编写 SQL。JPQL 查询的是实体对象而不是数据库表。
注解(Annotations):
- JPA 使用注解来描述实体类与数据库表之间的映射关系。例如,
@Entity
用于标识实体类,@Id
用于标识主键,@Column
用于定义列映射等。
事务管理:
- JPA 提供了对事务的支持,确保操作的原子性。它可以与 JTA(Java Transaction API)进行集成,实现分布式事务控制。
JPA 常见注解:
@Entity
:用于标识一个类是实体类,映射到数据库表。@Id
:用于指定实体类的主键。@GeneratedValue
:用于指定主键的生成策略。@Column
:用于指定实体类属性和数据库列之间的映射关系。@OneToMany
、@ManyToOne
、@ManyToMany
、@OneToOne
:用于定义实体类之间的关联关系。@Table
:用于指定数据库表的名称。@Query
:用于定义自定义的 JPQL 查询。
——————————————————————————————————————————————————
搭建一个 SpringBoot. 3.x + Hibernate + HQL查询的项目
Hibernate 是一个强大的 对象关系映射(ORM) 框架,它用于简化 Java 程序与关系型数据库之间的交互。ORM 的核心思想是将数据库表与 Java 对象进行映射,从而让开发者可以通过操作 Java 对象来实现对数据库的增、删、改、查等操作,避免了直接编写繁琐的 SQL 语句。个人感觉 Hibernate和 mybatis-plus的结构有些相似,都是使用了 ORM框架,但是 hibernate明显要更为复杂。
配置文件 pom.xml和 application.properties不做赘述。
(1) 首先创建 JPA实体类 person,对应的是数据库中的 person表:
1 | package org.kgty.sql_hibernate; |
(2) 其次创建仓库接口,在 Spring Data JPA
中,可以通过继承 JpaRepository
来快速创建一个数据访问层接口。 JpaRepository
接口中提供了许多现成的数据库查询方法,比如 findById()方法,等等。如果提供的数据库查询方法无法满足需求,开发可以进行自定义。
1 | package org.kgty.sql_hibernate.repository; |
使用默认的 findByUsername(String name)方法,数据库查询效果相当于
1 | select * from person where username = 'xxxx'; |
并且默认的查询方法使用了预编译,可以避免 sql注入。
(3) 除了使用默认提供的查询方法外,还可以使用 HQL构造查询语句来查询数据库,在服务层中使用:
HQL(Hibernate Query Language,Hibernate 查询语言)是 Hibernate 框架中提供的一种查询语言,它与 SQL 类似,但 HQL 主要用于操作 Hibernate 实体对象而不是数据库表。HQL 使开发者能够使用面向对象的语法进行数据库查询,它是 Hibernate 框架特有的语言,旨在简化数据库操作,并减少对底层数据库表的直接依赖。
1 | package org.kgty.sql_hibernate.service; |
(4) 创建controller层,路由中使用服务层方法,启动项目,成功访问,得到数据库回显数据:
1 | package org.kgty.sql_hibernate.controller; |
HQL中的 sql注入
参数直接拼接
1 | String hql = "FROM person p WHERE p.username = '"+username+"'"; |
HQL支持运行原生 SQL语句 - createNativeQuery()
,若直接拼接参数会造成 sql注入:
1 | Query query = (Query) entityManager.createNativeQuery("select * from person where username like '"+username+"'"); |
HQL中的预编译
为了避免 SQL注入,HQL给出了几种参数绑定方式,即同理预编译的占位符。
(1) 命名参数占位
1 | String hql = "FROM person p WHERE p.username = :username"; |
使用 : 后面跟输入参数的方式进行占位。
PS: 这个东西前段时间 京东面试的时候面试官问到了,当时只知道 ? 进行占位,完全没听说过冒号这个说法,现在看来是认知浅薄了。
占位符起到作用,进行了预编译:
(2) 位置参数占位
1 | String hql = "FROM person p WHERE p.username = ?1"; |
效果同理,预编译,不做赘述。
(3) 列表占位 (in查询)
1 | public List<person> getPersonByUsername(List<String> username) { |
使用列表可以进行批量查询:
同样会进行预编译: