面向接口编程的 ORM:从基础到实战

一、面向接口编程的 ORM

定义

ORM(Object-Relational Mapping,对象关系映射)是一种将 Java 对象与数据库表之间进行自动映射的技术。
JPA(Java Persistence API)是 Java 官方定义的一套 ORM 规范,而 Spring Data JPA 则是对 JPA 进行了进一步的封装和增强,提供了更便捷的开发体验。

核心思想:让 Java 对象和数据库表自动对应起来,你操作对象,框架帮你操作数据库。

在这里插入图片描述

核心三要素

组件 作用 示例
@Entity 标记 Java 类为数据库表映射 @Entity @Table(name = "user") public class User { ... }
Repository 数据访问接口(继承 JpaRepository<T, ID> public interface UserRepository extends JpaRepository<User, Long> {}
Query Methods 方法名自动解析为 SQL List<User> findByEmailAndStatus(String email, String status);

二、Query Methods:方法名即查询

原理

Spring Data JPA 在启动时会扫描 Repository 接口,根据方法名按规则生成 JPQL/HQL 查询。例如:

  • findByXxxWHERE xxx = ?
  • findByXxxIgnoreCase → 忽略大小写
  • findByXxxOrderByYyyDesc → 自动加 ORDER BY yyy DESC
示例
// Entity 类
@Entity
@Table(name = "user")//指定数据库表名
@Data // Lombok 自动生成 getter/setter/toString
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)//主键
    private Long id;

    private String userName;
    private String email;
    private String status;
}

// Repository 接口
public interface UserRepository extends JpaRepository<User, Long> {
    // 根据邮箱和状态查询用户
    List<User> findByEmailAndStatus(String email, String status);

    // 忽略大小写的邮箱查询
    List<User> findByEmailIgnoreCase(String email);

    // 按用户名降序排序
    List<User> findByStatusOrderByUserNameDesc(String status);
}

复杂查询

对于复杂的查询需求,建议使用 @Query 注解来编写原生 SQL 或 JPQL,避免方法名过长且难以维护。

public interface UserRepository extends JpaRepository<User, Long> {

    // 使用 @Query 编写复杂查询
    @Query("SELECT u FROM User u WHERE u.email LIKE %:email% AND u.status = :status")
    List<User> findUsersByEmailLike(@Param("email") String email, @Param("status") String status);
}

常用注解(新手速查)

注解 是否必须 典型用法 说明
@Entity ✅ 必须 类上 标记为实体
@Id ✅ 必须 主键字段 标记主键
@GeneratedValue ✅ 主键通常需要 主键字段 自动生成主键值
@Table ❌ 可选 类上 指定表名
@Column ❌ 可选 字段上 指定列名或加约束
@Transient ❌ 可选 字段上 排除字段不映射

三、动手实践:从零开始构建一个简单的 JPA 应用

1. 引入依赖

首先,在 pom.xml 中添加 Spring Boot 和 JPA 的依赖:

<dependencies>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Data JPA -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- MySQL Driver -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- Lombok for reducing boilerplate code -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

2. 配置数据源

application.yml 中配置数据库连接信息:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
    username: root
    password: your-password
    driver-class-name: com.mysql.cj.jdbc.Driver

  jpa:
    hibernate:
      ddl-auto: update # 自动创建和更新表结构
    show-sql: true # 打印生成的 SQL

3. 创建实体类

import lombok.Data;
import javax.persistence.*;

@Entity
@Table(name = "user")
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "user_name", nullable = false, length = 100)//描述字段如何映射到列,大多数情况可以省略(靠命名进行约定),除了列名不等于驼峰命名转换或者需要加约束
    private String userName;

    @Column(nullable = false, unique = true)
    private String email;

    private String status;
}

4. 创建 Repository 接口

import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;

public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByEmailAndStatus(String email, String status);

    List<User> findByEmailIgnoreCase(String email);

    List<User> findByStatusOrderByUserNameDesc(String status);
}

5. 创建 Service 层

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public List<User> getUsersByEmailAndStatus(String email, String status) {
        return userRepository.findByEmailAndStatus(email, status);
    }

    public List<User> getUsersByEmailIgnoreCase(String email) {
        return userRepository.findByEmailIgnoreCase(email);
    }

    public List<User> getUsersByStatusOrderByUserNameDesc(String status) {
        return userRepository.findByStatusOrderByUserNameDesc(status);
    }
}

6. 创建 Controller 层

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/users")
    public List<User> getUsers(
            @RequestParam(required = false) String email,
            @RequestParam(required = false) String status) {

        if (email != null && status != null) {
            return userService.getUsersByEmailAndStatus(email, status);
        } else if (email != null) {
            return userService.getUsersByEmailIgnoreCase(email);
        } else if (status != null) {
            return userService.getUsersByStatusOrderByUserNameDesc(status);
        } else {
            return userService.getUsersByStatusOrderByUserNameDesc("ACTIVE");
        }
    }
}

四、总结

  1. ORM 的核心概念:如何通过对象关系映射(ORM)简化数据库操作。
  2. JPA 和 Spring Data JPA 的使用:如何使用注解和方法名自动生成查询。
  3. 实际项目中的应用:从零开始构建一个简单的 JPA 应用,并展示了如何通过 @EntityRepositoryService 实现 CRUD 操作。

最后

  • 保持命名一致性:尽量让数据库字段名符合“下划线命名”规则(如 user_name),Java 字段名使用驼峰命名(如 userName)。这样可以减少不必要的 @Column 注解。
  • Lombok 简化代码:使用 @Data 注解可以自动生成 getter/setter/toString 方法,减少样板代码。
  • 合理使用 @Query:对于复杂的查询需求,使用 @Query 编写原生 SQL 或 JPQL,避免方法名过长且难以维护。
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐