Spring Boot ORM 快速指南



Spring Boot ORM - 概述

Spring 框架与 Hibernate、Java 持久性 API (JPA)、Java 数据对象 (JDO) 和 iBATIS SQL Maps 等 ORM 框架良好集成。Spring 提供资源管理、数据访问对象 (DAO) 实现和事务策略。Spring 允许通过依赖管理配置 ORM 库的功能。Spring 维持统一的 DAO 异常层次结构和所有支持的 ORM 库的通用事务管理。

Spring IoC 容器简化了 ORM 配置和部署。以下是使用 Spring 框架创建 ORM DAO 的主要优点:

  • 易于测试 - 使用 Spring IoC,可以轻松配置 ORM 实现。每个持久性单元都可以独立测试。

  • 公共数据访问异常 - Spring 将 ORM 工具异常包装到一个公共运行时异常 DataAccessException 中。这种方法有助于在适当的层处理大多数持久性异常(不可恢复)。无需处理 ORM 特定的样板 catch/throws/异常声明。

  • 通用资源管理 - Spring 应用程序上下文轻松管理持久性对象及其配置。例如,Hibernate SessionFactory 实例、JPA EntityManagerFactory 实例、JDBC DataSource 实例、iBatis SQL Maps 配置对象和其他相关对象。Spring 本身处理本地和 JTA 事务管理。

  • 集成事务管理 - Spring AOP 可用于使用 @Transaction 注解或在 XML 配置文件中指定事务 AOP 建议来使用声明性 AOP 风格的拦截器包装 ORM 代码。Spring 处理事务语义、异常处理、回滚等。Spring 允许交换事务管理器而不会影响 ORM 代码。

Spring Boot ORM - 环境设置

本章将指导您如何准备开发环境以开始使用 Spring 框架的工作。它还将教您如何在设置 Spring 框架之前在您的机器上设置 JDK、Tomcat 和 Eclipse -

步骤 1 - 设置 Java 开发工具包 (JDK)

Java SE 可免费下载。要下载,请点击此处,下载与您的操作系统兼容的版本。

按照说明下载 Java,并运行.exe文件在您的机器上安装 Java。在您的机器上安装 Java 后,您需要设置环境变量以指向正确的安装目录。

为 Windows 2000/XP 设置路径

假设您已将 Java 安装在 c:\Program Files\java\jdk 目录中 -

  • 右键单击“我的电脑”,然后选择“属性”。

  • 在“高级”选项卡下单击“环境变量”按钮。

  • 现在,编辑“Path”变量,并将 Java 可执行文件目录的路径添加到其末尾。例如,如果路径当前设置为C:\Windows\System32,则按以下方式编辑它

C:\Windows\System32;c:\Program Files\java\jdk\bin

为 Windows 95/98/ME 设置路径

假设您已将 Java 安装在 c:\Program Files\java\jdk 目录中 -

  • 编辑“C:\autoexec.bat”文件,并在末尾添加以下行 -

SET PATH=%PATH%;C:\Program Files\java\jdk\bin

为 Linux、UNIX、Solaris、FreeBSD 设置路径

应将环境变量 PATH 设置为指向已安装 Java 二进制文件的目录。如果您遇到问题,请参考您的 shell 文档。

例如,如果您使用 bash 作为您的 shell,那么您将在您的.bashrc文件的末尾添加以下行 -

export PATH=/path/to/java:$PATH'

或者,如果您使用集成开发环境 (IDE),例如 Borland JBuilder、Eclipse、IntelliJ IDEA 或 Sun ONE Studio,您将必须编译并运行一个简单的程序以确认 IDE 知道您已安装 Java 的位置。否则,您将必须按照 IDE 文档中给出的说明进行正确的设置。

步骤 2 - 设置 Spring Tool Suite

本教程中的所有示例都是使用 Spring Tool Suite IDE 编写的。因此,我们建议您应该在您的机器上安装最新版本的 Spring Tool Suite。

要安装 Spring Tool Suite IDE,请从www.eclipse.org/downloads下载最新的 Spring Tool Suite 二进制文件。下载安装程序后,将二进制分发版解压缩到方便的位置。例如,在 Windows 上为 C:\sts\sts-4.23.1.RELEASE,或在 Linux/Unix 上为 /usr/local/sts/sts-4.23.1.RELEASE,最后适当地设置 PATH 变量。

可以通过在 Windows 机器上执行以下命令启动 Spring Tool Suite,或者您可以简单地双击 SpringToolSuite4.exe

E:\sts\sts-4.23.1.RELEASE\SpringToolSuite4.exe 

可以通过在 Unix(Solaris、Linux 等)机器上执行以下命令启动 Eclipse -

$/usr/local/sts/sts-4.23.1.RELEASE/SpringToolSuite4

步骤 3 - 设置 Spring Boot 项目

现在,如果一切正常,您可以继续设置 Spring Boot。以下是将 Spring Boot 项目下载并安装到您的机器上的简单步骤。

  • 转到 spring Initializr 链接以创建 spring boot 项目,https://start.spring.io/

  • 选择项目为Maven 项目

  • 选择语言为Java

  • 选择 Spring Boot 版本为3.3.3

  • 设置项目元数据 - Group 为com.tutorialspoint,Artifact 为springbootorm,name 为springboot-h2,Description 为Spring Boot ORM 演示项目,包名为com.tutorialspoint.springbootorm

  • 选择打包方式为Jar

  • 选择 java 为21

  • 添加依赖项为Spring Web、Spring Data JPA、H2 数据库和 Spring Boot DevTools

现在单击“生成”按钮以生成项目结构。

Spring Initializr

下载基于 maven 的 spring boot 项目后,将 maven 项目导入 eclipse,其余的 eclipse 将会处理。它将下载 maven 依赖项并构建项目,使其准备好进行进一步开发。

步骤 4 - 用于 REST API 测试的 POSTMAN

POSTMAN 是一个用于测试基于 REST 的 API 的有用工具。要安装 POSTMAN,请从www.postman.com/downloads/下载最新的 POSTMAN 二进制文件。下载可安装文件后,按照说明进行安装和使用。

Spring Boot ORM - JPA

Java 持久性 API (JPA) 是一组类和接口,允许将 Java 对象与数据库进行对象/关系映射。在 JPA 中,实体类在persistence.xml文件中定义。Spring Boot 不使用persistence.xml。而是使用“实体扫描”,这是查找并将实体类与持久性提供程序注册的过程。

什么是实体扫描?

    扫描包 - JPA 提供程序扫描指定的包或目录以查找用@Entity注释的类。

  • 实体发现 - 当提供程序找到带有@Entity注释的类时,它会将其识别为持久性实体并将其注册。

  • 持久性单元 - 然后将发现的实体与持久性单元关联,持久性单元定义由单个EntityManager管理的一组实体。

默认情况下会扫描自动配置的包。

在 Spring Boot 中配置实体扫描

  • 默认扫描 - 默认情况下,Spring Boot 扫描主应用程序类的包及其子包以查找实体类。

  • 自定义扫描 - 您可以使用 @EntityScan 注解指定要扫描的包。例如

    @SpringBootApplication
    @EntityScan(basePackages = {"com.example.entities"})
    public class Application {
       // ...
    }
    

Spring Data JPA 存储库

Spring Data JPA 实现用于从数据库(关系型、NoSQL 或其他任何数据库)访问数据的接口。Spring Data 存储库扩展自RepositoryCrudRepository

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer>  {
}

创建和删除数据库

如果您使用嵌入式数据库(如 H2、Derby),JPA 数据库会自动创建。要创建和删除表,您的 application.properties 应如下所示 -

spring.jpa.hibernate.ddl-auto=create-drop

映射类之间的关联

关联映射可以分为两种类型 -

  • 单向关联 - 在这种关联中,只有一个实体持有对另一个实体的引用。例如,一对多或多对一关系。

  • 双向关联 - 在双向关联中,两个实体(源和目标)都有一个彼此引用的关系字段。例如,多对多关系。

一对多关系(单向)

想象一下部门实体及其员工。每个部门都有许多员工,但每个员工只属于一个部门。

Department.java

package com.tutorialspoint;

import javax.persistence.*;
import java.util.*;

@Entity
public class Department {
   @Id
   private Long id;

   @OneToMany
   @JoinColumn(name = "department_id")
   private List<Employee> employees;

   public Department() {}

   public Long getId() {
      return id;
   }

   public void setId(Long id) {
      this.id = id;
   }
   public List<Employee> getEmployees() {
      return employees;
   }
   public void setEmployees(List<Employee> employees) {
      this.employees = employees;
   }
}

Employee.java

package com.tutorialspoint;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Employee {
   @Id
   private Long id;

   public Long getId() {
      return id;
   }

   public void setId(Long id) {
      this.id = id;
   }
}

多对一关系(单向)

考虑一个学生和一个学校。每个学生只能在一个学校注册,但每个学校可以有多个学生。

Student.java

package com.tutorialspoint;

import javax.persistence.*;

@Entity
public class Student {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long id;
   private String name;

   @ManyToOne
   @JoinColumn(name = "school_id")
   private School school;

   public Long getId() {
      return id;
   }
   public void setId(Long id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public School getSchool() {
      return school;
   }
   public void setSchool(School school) {
      this.school = school;
   }
}

School.java

package com.tutorialspoint;

import javax.persistence.Entity;
import javax.persistence.Id;
import java.util.List;

@Entity
public class School {
   @Id
   private Long id;
   private List<Student> students;
	
   public Long getId() {
      return id;
   }
   public void setId(Long id) {
      this.id = id;
   }
   public List<Student> getStudents() {
      return students;
   }
   public void setStudents(List<Student> students) {
      this.students = students;
   }
}

多对多关系(双向)

在双向关联中,两个实体(源和目标)都有一个彼此引用的关系字段。想象一下书籍和作者。每本书有一位作者,但每位作者可以编写多本书。

Book.java

package com.tutorialspoint;

import javax.persistence.*;

@Entity
public class Book {
   @Id
   private Long id;
   private String title;

   @ManyToOne
   @JoinColumn(name = "author_id")
   private Author author;
   
   public Long getId() {
      return id;
   }
   public void setId(Long id) {
      this.id = id;
   }
   public String getTitle() {
      return title;
   }
   public void setTitle(String title) {
      this.title = title;
   }
   public Author getAuthor() {
      return author;
   }
   public void setAuthor(Author author) {
      this.author = author;
   }
}

Author.java

package com.tutorialspoint;

import javax.persistence.*;
import java.util.List;

@Entity
public class Author {

   @Id
   private Long id;
   private String name;
   
   @OneToMany(mappedBy = "author")
   private List<Book> books;

   public Long getId() {
      return id;
   }
   public void setId(Long id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public List<Book> getBooks() {
      return books;
   }
   public void setBooks(List<Book> books) {
      this.books = books;
   }
}

Spring Boot ORM - 创建项目

使用 STS(Spring Tool Suite),选择文件->导入->现有 Maven 项目,然后单击下一步。

Import Maven Project

选择在环境设置期间从 spring initializr 下载并解压缩的项目,如下所示

Import Maven Project Browse

单击“完成”按钮,将创建一个新项目。

Spring Application

现在我们的项目已准备就绪,让我们检查 pom.xml 中的以下依赖项。

  • Spring Boot 启动器框架库

  • MySQL 连接器

  • 其他相关依赖项。

由于我们使用的是 spring boot,因此其启动器项目会自动处理大多数依赖项。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>3.3.3</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.tutorialspoint</groupId>
   <artifactId>springbootorm</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>springbootorm</name>
   <description>Demo project for Spring Boot ORM</description>
   <url/>
   <licenses>
      <license/>
   </licenses>
   <developers>
      <developer/>
   </developers>
   <scm>
      <connection/>
      <developerConnection/>
      <tag/>
      <url/>
   </scm>
   <properties>
      <java.version>21</java.version>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-data-jpa</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-devtools</artifactId>
         <scope>runtime</scope>
         <optional>true</optional>
      </dependency>
      <dependency>
         <groupId>com.mysql</groupId>
         <artifactId>mysql-connector-j</artifactId>
         <scope>runtime</scope>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>
   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>
</project>

Spring Boot ORM - application.properties

Spring Boot 从 `application.properties` 文件中读取应用程序和持久化相关的属性。在这里,我们也可以配置Hibernate或其他ORM框架的特定属性。我们使用通用的属性,以便可以在不更改太多代码的情况下在不同的ORM之间切换。默认情况下,如果在**POM.xml**中未指定其他ORM库,Spring Boot会将Hibernate配置为ORM提供程序。

在**src -> main -> resources**目录下创建**application.properties**文件,并按如下所示更新。

application.properties

spring.application.name=springbootorm
#datasource configurations
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tutorialspoint
spring.datasource.username=root
spring.datasource.password=root@123
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# show SQL
spring.jpa.show-sql: true
# DDL generation
spring.jpa.generate-ddl=true

以下是application.properties文件中关键属性的描述。

  • **spring.datasource** - 数据库特定属性,例如连接URL、用户名、密码、驱动程序类等。

  • **spring.jpa** - JPA特定属性,例如显示SQL,允许创建表等。

Spring Boot ORM - 更新项目

现在让我们为Spring应用程序添加一个REST API,它可以添加、编辑、删除和显示员工信息。

实体

创建一个名为Employee的实体,以将Employee对象持久化到Employee表。

Employee.java

package com.tutorialspoint.springbootorm.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

// entity class to persist object to Employee Table
@Entity
public class Employee {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private int id;
   private String name;
   private int age;
   private String email;

   // setter, getter methods
   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public int getAge() {
      return age;
   }

   public void setAge(int age) {
      this.age = age;
   }

   public String getEmail() {
      return email;
   }

   public void setEmail(String email) {
      this.email = email;
   }
}

仓库 (Repository)

创建一个仓库来对Employee对象执行数据库操作。

EmployeeRepository.java

package com.tutorialspoint.springbootorm.repository;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import com.tutorialspoint.springbootorm.entity.Employee;

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer>  {
}

服务 (Service)

创建一个服务来调用仓库实例,对Employee对象执行数据库操作。

EmployeeService.java

package com.tutorialspoint.springbootorm.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.tutorialspoint.springbootorm.entity.Employee;
import com.tutorialspoint.springbootorm.repository.EmployeeRepository;

@Service
public class EmployeeService {

   @Autowired
   EmployeeRepository repository;

   // get an employee by id
   public Employee getEmployeeById(int id) {
      return repository.findById(id).get();
   }

   // get list of all employees
   public List<Employee> getAllEmployees(){
      List<Employee> employees = new ArrayList<Employee>();
      repository.findAll().forEach(employee -> employees.add(employee));
      return employees;
   }

   // create or update an employee
   public void saveOrUpdate(Employee employee) {
      repository.save(employee);
   }
   
   // delete the employee
   public void deleteEmployeeById(int id) {
      repository.deleteById(id);
   }
}

控制器 (Controller)

为REST API创建一个控制器。

EmployeeController.java

package com.tutorialspoint.springbootorm.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.tutorialspoint.springbootorm.entity.Employee;
import com.tutorialspoint.springbootorm.service.EmployeeService;

@RestController
@RequestMapping(path = "/emp")
public class EmployeeController {

   @Autowired
   EmployeeService employeeService;

   // GET mapping to get all the employees
   @GetMapping("/employees")
   public List<Employee> getAllEmployees(){
      return employeeService.getAllEmployees();
   }

   // GET mapping to get an employee by id
   @GetMapping("/employee/{id}")
   public Employee getEmployee(@PathVariable("id") int id) {
      return employeeService.getEmployeeById(id);
   }

   // DELETE mapping to delete an employee by id
   @DeleteMapping("/employee/{id}")
   public void deleteEmployee(@PathVariable("id") int id) {
      employeeService.deleteEmployeeById(id);
   }

   // POST mapping to create a new employee
   @PostMapping("/employee")
   public void addEmployee(@RequestBody Employee employee) {
      employeeService.saveOrUpdate(employee);
   }
   
   // PUT mapping to update an employee
   @PutMapping("/employee")
   public void updateEmployee(@RequestBody Employee employee) {
      employeeService.saveOrUpdate(employee);
   }	
}

主应用程序

启动应用程序的主应用程序类。

SpringBootOrmApplication.java

package com.tutorialspoint.springbootorm;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

// Main Application
@SpringBootApplication
public class SpringBootOrmApplication {
   public static void main(String[] args) {
      SpringApplication.run(SpringBootOrmApplication.class, args);
   }
}

Spring Boot ORM - 测试项目

现在在STS中,右键单击springbootorm项目,选择**Run As -> Spring Boot App**上下文 -

Run As Spring Boot App

输出

您将在STS控制台中看到类似的结果。

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

[32m :: Spring Boot :: [39m              [2m (v3.3.3)[0;39m

[2m2024-08-28T15:38:41.453+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mc.t.s.SpringbootormApplication          [0;39m [2m:[0;39m Starting SpringbootormApplication using Java 21.0.3 with PID 4760 (E:\springbootorm\target\classes started by Tutorialspoint in E:\springbootorm)
[2m2024-08-28T15:38:41.456+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mc.t.s.SpringbootormApplication          [0;39m [2m:[0;39m No active profile set, falling back to 1 default profile: "default"
[2m2024-08-28T15:38:41.517+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36m.e.DevToolsPropertyDefaultsPostProcessor[0;39m [2m:[0;39m Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
[2m2024-08-28T15:38:41.517+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36m.e.DevToolsPropertyDefaultsPostProcessor[0;39m [2m:[0;39m For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
[2m2024-08-28T15:38:42.164+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36m.s.d.r.c.RepositoryConfigurationDelegate[0;39m [2m:[0;39m Bootstrapping Spring Data JPA repositories in DEFAULT mode.
[2m2024-08-28T15:38:42.214+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36m.s.d.r.c.RepositoryConfigurationDelegate[0;39m [2m:[0;39m Finished Spring Data repository scanning in 43 ms. Found 1 JPA repository interface.
[2m2024-08-28T15:38:42.781+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mo.s.b.w.embedded.tomcat.TomcatWebServer [0;39m [2m:[0;39m Tomcat initialized with port 8080 (http)
[2m2024-08-28T15:38:42.797+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mo.apache.catalina.core.StandardService  [0;39m [2m:[0;39m Starting service [Tomcat]
[2m2024-08-28T15:38:42.797+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mo.apache.catalina.core.StandardEngine   [0;39m [2m:[0;39m Starting Servlet engine: [Apache Tomcat/10.1.28]
[2m2024-08-28T15:38:42.848+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mo.a.c.c.C.[Tomcat].[localhost].[/]      [0;39m [2m:[0;39m Initializing Spring embedded WebApplicationContext
[2m2024-08-28T15:38:42.848+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mw.s.c.ServletWebServerApplicationContext[0;39m [2m:[0;39m Root WebApplicationContext: initialization completed in 1330 ms
[2m2024-08-28T15:38:42.969+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mcom.zaxxer.hikari.HikariDataSource      [0;39m [2m:[0;39m HikariPool-1 - Starting...
[2m2024-08-28T15:38:43.457+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mcom.zaxxer.hikari.pool.HikariPool       [0;39m [2m:[0;39m HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@3c6da728
[2m2024-08-28T15:38:43.459+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mcom.zaxxer.hikari.HikariDataSource      [0;39m [2m:[0;39m HikariPool-1 - Start completed.
[2m2024-08-28T15:38:43.504+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mo.hibernate.jpa.internal.util.LogHelper [0;39m [2m:[0;39m HHH000204: Processing PersistenceUnitInfo [name: default]
[2m2024-08-28T15:38:43.564+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36morg.hibernate.Version                   [0;39m [2m:[0;39m HHH000412: Hibernate ORM core version 6.5.2.Final
[2m2024-08-28T15:38:43.600+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mo.h.c.internal.RegionFactoryInitiator   [0;39m [2m:[0;39m HHH000026: Second-level cache disabled
[2m2024-08-28T15:38:43.934+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mo.s.o.j.p.SpringPersistenceUnitInfo     [0;39m [2m:[0;39m No LoadTimeWeaver setup: ignoring JPA class transformer
[2m2024-08-28T15:38:44.909+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mo.h.e.t.j.p.i.JtaPlatformInitiator      [0;39m [2m:[0;39m HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
Hibernate: create table employee (id integer not null auto_increment, age integer not null, email varchar(255), name varchar(255), primary key (id)) engine=InnoDB
[2m2024-08-28T15:38:45.141+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mj.LocalContainerEntityManagerFactoryBean[0;39m [2m:[0;39m Initialized JPA EntityManagerFactory for persistence unit 'default'
[2m2024-08-28T15:38:45.431+05:30[0;39m [33m WARN[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mJpaBaseConfiguration$JpaWebConfiguration[0;39m [2m:[0;39m spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
[2m2024-08-28T15:38:45.862+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mo.s.b.d.a.OptionalLiveReloadServer      [0;39m [2m:[0;39m LiveReload server is running on port 35729
[2m2024-08-28T15:38:45.901+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mo.s.b.w.embedded.tomcat.TomcatWebServer [0;39m [2m:[0;39m Tomcat started on port 8080 (http) with context path '/'
[2m2024-08-28T15:38:45.909+05:30[0;39m [32m INFO[0;39m [35m4760[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mc.t.s.SpringbootormApplication          [0;39m [2m:[0;39m Started SpringbootormApplication in 4.891 seconds (process running for 5.804)

添加员工

服务器启动并运行后,使用Postman发出POST请求以首先添加记录。

在Postman中设置以下参数。

  • HTTP方法 - **POST**

  • URL - **https://127.0.0.1:8080/emp/employee**

  • BODY - **员工JSON数据**

{   
   "age": "35",  
   "name": "Julie",  
   "email": "[email protected]"  
}   

单击“发送”按钮并检查响应状态是否为OK。

Add an Employee

获取所有员工

现在发出GET请求以获取所有记录。

在Postman中设置以下参数。

  • HTTP方法 - **GET**

  • URL - **https://127.0.0.1:8080/emp/employees**

单击发送按钮并验证响应。

[{  
   "id": 1,  
   "age": 35,  
   "name": "Julie",  
   "email": "[email protected]"  
}]   
Get all Employees

Spring Boot ORM - EclipseLink集成

Spring Boot默认使用Hibernate作为ORM实现。为了使用EclipseLink,我们首先需要从**pom.xml**中的**spring-data-jpa**依赖项中排除Hibernate依赖项。

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
   <exclusions>
      <exclusion>
         <groupId>org.hibernate</groupId>
         <artifactId>hibernate-entitymanager</artifactId>
      </exclusion>
      <exclusion>
         <groupId>org.hibernate</groupId>
         <artifactId>hibernate-core</artifactId>
      </exclusion>
   </exclusions>
</dependency>

现在在**pom.xml**中包含eclipse-link依赖项。

<dependency>
   <groupId>org.eclipse.persistence</groupId>
   <artifactId>org.eclipse.persistence.jpa</artifactId>
   <version>4.0.4</version>
</dependency>

以下是完整的**pom.xml**文件

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>3.3.3</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.tutorialspoint</groupId>
   <artifactId>springbootorm</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>springbootorm</name>
   <description>Demo project for Spring Boot ORM</description>
   <url/>
   <licenses>
      <license/>
   </licenses>
   <developers>
      <developer/>
   </developers>
   <scm>
      <connection/>
      <developerConnection/>
      <tag/>
      <url/>
   </scm>
   <properties>
      <java.version>21</java.version>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-data-jpa</artifactId>
         <exclusions>
            <exclusion>
               <groupId>org.hibernate</groupId>
               <artifactId>hibernate-entitymanager</artifactId>
            </exclusion>
            <exclusion>
               <groupId>org.hibernate</groupId>
               <artifactId>hibernate-core</artifactId>
            </exclusion>
         </exclusions>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
         <groupId>org.eclipse.persistence</groupId>
         <artifactId>org.eclipse.persistence.jpa</artifactId>
         <version>4.0.4</version>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-devtools</artifactId>
         <scope>runtime</scope>
         <optional>true</optional>
      </dependency>
      <dependency>
         <groupId>com.mysql</groupId>
         <artifactId>mysql-connector-j</artifactId>
         <scope>runtime</scope>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>
   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>
</project>

保存文件,Eclipse将自动更新依赖项。

Spring Boot ORM - 更新项目以使用EclipseLink

Spring Boot使用**HibernateJpaAutoConfiguration**,默认情况下配置Hibernate实现。为了切换到EclipseLink,我们需要创建一个自定义配置类,该类将扩展JpaBaseConfiguration类。JpaBaseConfiguration是用于扩展和配置任何ORM实现的JPA的基类。以下是EclipsLinkJpaConfiguration的代码。

JPA配置

创建EclipseLink配置类。

EclipsLinkJpaConfiguration.java

package com.tutorialspoint.springbootorm;

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.logging.SessionLog;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
import org.springframework.transaction.jta.JtaTransactionManager;

// EclipseLink Specific Configuration Class
@Configuration
public class EclipsLinkJpaConfiguration extends JpaBaseConfiguration {

   protected EclipsLinkJpaConfiguration(DataSource dataSource, JpaProperties properties,
      ObjectProvider<JtaTransactionManager> jtaTransactionManager) {
      super(dataSource, properties, jtaTransactionManager);
   }

   // EclipseLink JPA Adaptor
   @Override
   protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
      return new EclipseLinkJpaVendorAdapter();
   }

   // EclipseLink Properties
   @Override
   protected Map<String, Object> getVendorProperties() {
      Map<String, Object> map = new HashMap<>();
      map.put(PersistenceUnitProperties.WEAVING, "false");
      map.put(PersistenceUnitProperties.LOGGING_LEVEL, SessionLog.FINER_LABEL); 
      map.put(PersistenceUnitProperties.DDL_GENERATION, PersistenceUnitProperties.CREATE_ONLY);
      map.put(PersistenceUnitProperties.LOGGING_LEVEL, SessionLog.FINER_LABEL); 
      return map;
   }

   // Database Connection properties setup
   @Bean
   public static DataSource dataSource() {
      final DriverManagerDataSource dataSource = new DriverManagerDataSource();
      dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
      dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/tutorialspoint");
      dataSource.setUsername("root");
      dataSource.setPassword("root@123");
      return dataSource;
   }
}

我们分别使用`createJpaVendorAdapter()`、`dataSource()`和`getVendorProperties()`方法添加了适配器、数据源和属性。

更新实体

同样更新实体,使用Integer代替int。

Employee.java

package com.tutorialspoint.springbootorm.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

// entity class to persist object to Employee Table
@Entity
public class Employee {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Integer id;
   private String name;
   private Integer age;
   private String email;

   // setter, getter methods
   public Integer getId() {
      return id;
   }

   public void setId(Integer id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public Integer getAge() {
      return age;
   }

   public void setAge(Integer age) {
      this.age = age;
   }

   public String getEmail() {
      return email;
   }

   public void setEmail(String email) {
      this.email = email;
   }
}

Spring Boot ORM - 测试 EclipseLink

现在在STS中,右键单击springbootorm项目,选择**Run As -> Spring Boot App**上下文 -

Run As Spring Boot App

输出

您将在STS控制台中看到类似的结果。

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

[32m :: Spring Boot :: [39m              [2m (v3.3.3)[0;39m

[2m2024-08-29T09:27:56.504+05:30[0;39m [32m INFO[0;39m [35m4004[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mc.t.s.SpringbootormApplication          [0;39m [2m:[0;39m Starting SpringbootormApplication using Java 21.0.3 with PID 4004 (E:\springbootorm\target\classes started by Tutorialspoint in E:\springbootorm)
...
[EL Config]: metadata: 2024-08-29 09:28:00.503--ServerSession(46117356)--Thread(Thread[#38,restartedMain,5,main])--The alias name for the entity class [class com.tutorialspoint.springbootorm.entity.Employee] is being defaulted to: Employee.
[EL Config]: metadata: 2024-08-29 09:28:00.508--ServerSession(46117356)--Thread(Thread[#38,restartedMain,5,main])--The table name for entity [class com.tutorialspoint.springbootorm.entity.Employee] is being defaulted to: EMPLOYEE.
[EL Config]: metadata: 2024-08-29 09:28:00.528--ServerSession(46117356)--Thread(Thread[#38,restartedMain,5,main])--The column name for element [name] is being defaulted to: NAME.
[EL Config]: metadata: 2024-08-29 09:28:00.533--ServerSession(46117356)--Thread(Thread[#38,restartedMain,5,main])--The column name for element [id] is being defaulted to: ID.
[EL Config]: metadata: 2024-08-29 09:28:00.534--ServerSession(46117356)--Thread(Thread[#38,restartedMain,5,main])--The column name for element [age] is being defaulted to: AGE.
[EL Config]: metadata: 2024-08-29 09:28:00.535--ServerSession(46117356)--Thread(Thread[#38,restartedMain,5,main])--The column name for element [email] is being defaulted to: EMAIL.
[EL Finer]: metamodel: 2024-08-29 09:28:00.567--ServerSession(46117356)--Thread(Thread[#38,restartedMain,5,main])--Canonical Metamodel class [com.tutorialspoint.springbootorm.entity.Employee_] not found during initialization.
[2m2024-08-29T09:28:00.568+05:30[0;39m [32m INFO[0;39m [35m4004[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mj.LocalContainerEntityManagerFactoryBean[0;39m [2m:[0;39m Initialized JPA EntityManagerFactory for persistence unit 'default'
[EL Finer]: 2024-08-29 09:28:00.634--Thread(Thread[#38,restartedMain,5,main])--initializing session manager
[EL Info]: 2024-08-29 09:28:00.638--ServerSession(46117356)--Thread(Thread[#38,restartedMain,5,main])--EclipseLink, version: Eclipse Persistence Services - 4.0.4.v202407190748-059428cdd2583c46f1f3e50d235854840a6fa9a7
[EL Fine]: connection: 2024-08-29 09:28:01.166--Thread(Thread[#38,restartedMain,5,main])--Detected database platform: org.eclipse.persistence.platform.database.MySQLPlatform
[EL Fine]: connection: 2024-08-29 09:28:01.179--ServerSession(46117356)--Connection(2116562590)--Thread(Thread[#38,restartedMain,5,main])--connecting(DatabaseLogin(
	platform=>MySQLPlatform
	user name=> ""
	connector=>JNDIConnector datasource name=>null
))
[EL Config]: connection: 2024-08-29 09:28:01.225--ServerSession(46117356)--Connection(1122916129)--Thread(Thread[#38,restartedMain,5,main])--Connected: jdbc:mysql://127.0.0.1:3306/tutorialspoint
	User: root@localhost
	Database: MySQL  Version: 8.0.39
	Driver: MySQL Connector/J  Version: mysql-connector-j-8.3.0 (Revision: 805f872a57875f311cb82487efcfb070411a3fa0)
[EL Fine]: connection: 2024-08-29 09:28:01.226--ServerSession(46117356)--Connection(610477732)--Thread(Thread[#38,restartedMain,5,main])--connecting(DatabaseLogin(
	platform=>MySQLPlatform
	user name=> ""
	connector=>JNDIConnector datasource name=>null
))
[EL Config]: connection: 2024-08-29 09:28:01.253--ServerSession(46117356)--Connection(1814465297)--Thread(Thread[#38,restartedMain,5,main])--Connected: jdbc:mysql://127.0.0.1:3306/tutorialspoint
	User: root@localhost
	Database: MySQL  Version: 8.0.39
	Driver: MySQL Connector/J  Version: mysql-connector-j-8.3.0 (Revision: 805f872a57875f311cb82487efcfb070411a3fa0)
[EL Fine]: connection: 2024-08-29 09:28:01.29--ServerSession(46117356)--Thread(Thread[#38,restartedMain,5,main])--/file:/E:/springbootorm/target/classes/_default login successful
...
[2m2024-08-29T09:28:02.343+05:30[0;39m [32m INFO[0;39m [35m4004[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mo.s.b.d.a.OptionalLiveReloadServer      [0;39m [2m:[0;39m LiveReload server is running on port 35729
[2m2024-08-29T09:28:02.377+05:30[0;39m [32m INFO[0;39m [35m4004[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mo.s.b.w.embedded.tomcat.TomcatWebServer [0;39m [2m:[0;39m Tomcat started on port 8080 (http) with context path '/'
[2m2024-08-29T09:28:02.385+05:30[0;39m [32m INFO[0;39m [35m4004[0;39m [2m---[0;39m [2m[springbootorm] [  restartedMain][0;39m [2m[0;39m[36mc.t.s.SpringbootormApplication          [0;39m [2m:[0;39m Started SpringbootormApplication in 6.895 seconds (process running for 8.546)

获取所有员工

现在发出GET请求以获取所有记录。

在Postman中设置以下参数。

  • HTTP方法 - **GET**

  • URL - **https://127.0.0.1:8080/emp/employees**

单击发送按钮并验证响应。

[{  
   "id": 1,  
   "age": 35,  
   "name": "Julie",  
   "email": "[email protected]"  
}]   
Get all Employees

您将在STS控制台中看到类似的更新。

[EL Finer]: connection: 2024-08-29 09:31:20.416--ServerSession(46117356)--Thread(Thread[#50,http-nio-8080-exec-1,5,main])--client acquired: 1215821283
[EL Finer]: transaction: 2024-08-29 09:31:20.43--ClientSession(1215821283)--Thread(Thread[#50,http-nio-8080-exec-1,5,main])--acquire unit of work: 2007319936
[EL Finer]: transaction: 2024-08-29 09:31:20.498--UnitOfWork(2007319936)--Thread(Thread[#50,http-nio-8080-exec-1,5,main])--begin unit of work flush
[EL Finer]: transaction: 2024-08-29 09:31:20.498--UnitOfWork(2007319936)--Thread(Thread[#50,http-nio-8080-exec-1,5,main])--end unit of work flush
[EL Fine]: sql: 2024-08-29 09:31:20.55--ServerSession(46117356)--Connection(135997463)--Thread(Thread[#50,http-nio-8080-exec-1,5,main])--SELECT ID, AGE, EMAIL, NAME FROM EMPLOYEE
[EL Finer]: transaction: 2024-08-29 09:31:20.599--UnitOfWork(2007319936)--Thread(Thread[#50,http-nio-8080-exec-1,5,main])--begin unit of work commit
[EL Finer]: transaction: 2024-08-29 09:31:20.599--UnitOfWork(2007319936)--Thread(Thread[#50,http-nio-8080-exec-1,5,main])--end unit of work commit
[EL Finer]: transaction: 2024-08-29 09:31:20.599--UnitOfWork(2007319936)--Thread(Thread[#50,http-nio-8080-exec-1,5,main])--resume unit of work
[EL Finer]: transaction: 2024-08-29 09:31:20.731--UnitOfWork(2007319936)--Thread(Thread[#50,http-nio-8080-exec-1,5,main])--release unit of work
[EL Finer]: connection: 2024-08-29 09:31:20.731--ClientSession(1215821283)--Thread(Thread[#50,http-nio-8080-exec-1,5,main])--client released
广告