一. 前言:
MyBatis 和 JPA(Java Persistence API)都是在开发中常见的工具,本篇文章主要讲述为什么需要这样的框架,两者的差异以及在springboot中如何配置的两者操纵数据库。
二. 框架介绍:
MyBatis 和 JPA(Java Persistence API)都是 Java 中常用的持久化框架(与数据库操纵以及管理的框架)传统的应用直接在代码中使用sql(JDBC)与数据库交互,由于纯用sql操纵数据库太复杂麻烦,为了简化应用程序与数据库操作,加了中间层,用来简化 SQL 编写、查询和数据管理。
SQL 与数据库交互的方式缺点
String sql = "SELECT id, name, age FROM users WHERE id = 1";
resultSet = statement.executeQuery(sql);
// 5. 处理结果集
if (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
System.out.println("User: " + name + ", Age: " + age);
}
这个方法的缺点:
-
管理难度:
- 在代码中,我们直接写了
SELECT
查询语句。每次要改变 SQL 逻辑时,需要手动修改代码,且 SQL 语句通常会分散在代码的各个地方,增加了管理的难度。在大型项目中,SQL 查询可能会变得非常复杂。如果每个查询都需要手动写在代码中,代码的可维护性将急剧下降。当数据库结构发生变化时,所有受影响的查询都必须手动修改。
- 在代码中,我们直接写了
-
安全问题:
-
直接拼接 SQL 语句容易导致 SQL 注入 问题。例如,以下代码如果未做适当的处理,会有 SQL 注入风险:
String sql = "SELECT * FROM users WHERE name = '" + userInput + "'"; // 潜在 SQL 注入风险
-
恶意用户可以通过输入特定的 SQL 语句来执行危险的操作,破坏数据库或窃取数据。预编译语句(
PreparedStatement
)可以避免此类问题,但传统的Statement
不会自动处理。使用ORM就可以使得恶意用户无法直接操纵sql,保证应用安全。
-
为什么不推荐直接使用 SQL 的例子
假设有一个团队开发了一个大型的电商系统,系统中有多个模块:用户管理、订单管理、商品管理等。每个模块都需要与数据库进行交互。
-
模块化开发时的痛点:
- 每个模块都写自己的 JDBC 代码,维护不同的 SQL 查询,造成了大量的重复代码。例如,一个用户模块和一个订单模块都需要写
SELECT
查询、INSERT
插入等操作,都会涉及相同的数据库连接和关闭资源的逻辑。 - 当需要修改数据库表结构时,比如增加字段、修改表名等,每个查询的代码都需要重新修改,这将非常繁琐且容易出错。
- 每个模块都写自己的 JDBC 代码,维护不同的 SQL 查询,造成了大量的重复代码。例如,一个用户模块和一个订单模块都需要写
-
安全性问题:
- 假设某个开发人员没有使用
PreparedStatement
来执行查询,而是直接拼接用户输入的参数,这将导致 SQL 注入 的风险。例如,在订单管理模块中,查询订单时,用户输入的订单号被直接拼接到 SQL 查询中,攻击者通过特殊输入可以恶意修改 SQL 语句,从而访问到不该看到的数据。
- 假设某个开发人员没有使用
-
代码的可读性和可维护性差:
- 由于 SQL 查询被硬编码在代码中,当业务需求发生变化时,需要在大量的代码中进行修改。而且,开发人员可能并不熟悉某些复杂的 SQL 查询,导致出错的几率增大,尤其是在系统规模不断增大的情况下。
因此,大多数现代应用程序都会选择使用 ORM 框架(如 Hibernate、JPA、MyBatis 等)来简化与数据库的交互,减少手动编写 SQL 的需求,同时提高代码的可维护性、安全性和可读性。
三. JPA:
3.1什么是JPA
JPA 是 Java 提供的官方标准 API,它是一个全自动的 ORM(Object Relational Mapping(对象关系映射)) 框架。JPA 基于 Java 类和数据库表之间的映射,自动完成对象与数据库之间的转换,开发者无需手动编写 SQL 语句。最常用的 JPA 实现是 Hibernate。
可以看到下面的层次图,JPA的设计思想是让开发者无感底层的数据库,这句话是什么意思呢,JPA将数据库的实体关系完全的映射到了java的对象,框架会根据实体类自动生成对应的 SQL 语句,用户直接使用方法操纵对象,而无需关注sql的编写。
3.2JPA代码
由下面的代码,就能知道什么是实体关系完全的映射到了java的对象。下图是一个是一个实体,在数据库中的主键外键各种属性等都需要映射到这张表中。
- 主键字段 (transaction_id) 使用 @Id 注解,并由数据库自动生成。
- 外键字段 (user_id) 使用 @ManyToOne 和 @JoinColumn 注解,表示多对一关系,即每个交易数据都关联到一个用户。
- 普通字段(如 productId, unitPrice, salesAmount)使用 @Column 注解与数据库中的相应列进行映射。
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.*;
import java.math.BigDecimal;
/*交易数据*/
@jakarta.persistence.Entity
@Table(name="transactions")
public class Transaction {
/*交易数据的条数,自增*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@JsonIgnore // 确保在 JSON 中不包括该字段
private Integer transaction_id;
/*产品的 id ,后续也可以根据需要改为产品名称*/
@Column(name = "