package com.example.accessingdatamysql;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity // This tells Hibernate to make a table out of this class
public class User {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private String email;
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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
使用 MySQL 访问数据
本指南将引导你完成创建连接到 MySQL 数据库的 Spring 应用程序的过程(与其他大多数指南和许多示例应用程序使用的内存嵌入式数据库不同)。它使用 Spring Data JPA 访问数据库,但这只是众多可能选择中的一种(例如,你可以使用纯粹的 Spring JDBC)。
你将构建什么
你将创建一个 MySQL 数据库,构建一个 Spring 应用程序,并将其连接到新创建的数据库。
MySQL 使用 GPL 许可,因此你随之分发的任何程序二进制文件也必须使用 GPL。请参阅GNU 通用公共许可。 |
你需要准备什么
-
大约 15 分钟
-
你喜欢的文本编辑器或 IDE
-
Java 17 或更高版本
如何完成本指南
要在你的本地环境中查看最终结果,你可以执行以下操作之一:
-
下载并解压本指南的源代码仓库
-
使用 Git 克隆仓库:
git clone https://github.com/spring-guides/gs-accessing-data-mysql.git
-
Fork 该仓库,以便你通过提交拉取请求来建议对本指南的更改
设置 MySQL 数据库
在构建应用程序之前,你需要先配置一个 MySQL 数据库。本指南假定你使用Spring Boot Docker Compose 支持。此方法的前提是你的开发机器上有一个可用的 Docker 环境,例如Docker Desktop。添加一个执行以下操作的依赖 spring-boot-docker-compose
:
-
在工作目录中搜索
compose.yml
和其他常用的 Compose 文件名 -
使用找到的
compose.yml
调用docker compose up
-
为每个支持的容器创建服务连接 Bean
-
应用程序关闭时调用
docker compose stop
要使用 Docker Compose 支持,你只需要遵循本指南即可。根据你引入的依赖,Spring Boot 会找到正确的 compose.yml
文件并在你运行应用程序时启动你的 Docker 容器。
从 Spring Initializr 开始
你可以使用此预初始化的项目并点击“生成”下载 ZIP 文件。该项目已配置好,适用于本教程中的示例。
手动初始化项目
-
导航到https://start.spring.io。此服务会引入应用程序所需的所有依赖,并为你完成大部分设置。
-
选择 Gradle 或 Maven,以及你想使用的语言。本指南假定你选择了 Java。
-
点击 Dependencies 并选择 Spring Web、Spring Data JPA、MySQL Driver、Docker Compose Support 和 Testcontainers。
-
点击 Generate。
-
下载生成的 ZIP 文件,这是一个根据你的选择配置好的 Web 应用程序归档。
如果你的 IDE 集成了 Spring Initializr,你可以从 IDE 中完成此过程。 |
创建 @Entity
模型
你需要创建实体模型,如下面的列表所示(位于 src/main/java/com/example/accessingdatamysql/User.java
中):
Hibernate 会自动将实体转换为表。
创建 Repository
你需要创建用于持有用户记录的 repository,如下面的列表所示(位于 src/main/java/com/example/accessingdatamysql/UserRepository.java
中):
package com.example.accessingdatamysql;
import org.springframework.data.repository.CrudRepository;
import com.example.accessingdatamysql.User;
// This will be AUTO IMPLEMENTED by Spring into a Bean called userRepository
// CRUD refers Create, Read, Update, Delete
public interface UserRepository extends CrudRepository<User, Integer> {
}
Spring 会自动将此 repository 接口实现为一个同名(大小写有变化——它被称为 userRepository
)的 bean。
创建 Controller
你需要创建一个 controller 来处理发送到应用程序的 HTTP 请求,如下面的列表所示(位于 src/main/java/com/example/accessingdatamysql/MainController.java
中):
package com.example.accessingdatamysql;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller // This means that this class is a Controller
@RequestMapping(path="/demo") // This means URL's start with /demo (after Application path)
public class MainController {
@Autowired // This means to get the bean called userRepository
// Which is auto-generated by Spring, we will use it to handle the data
private UserRepository userRepository;
@PostMapping(path="/add") // Map ONLY POST Requests
public @ResponseBody String addNewUser (@RequestParam String name
, @RequestParam String email) {
// @ResponseBody means the returned String is the response, not a view name
// @RequestParam means it is a parameter from the GET or POST request
User n = new User();
n.setName(name);
n.setEmail(email);
userRepository.save(n);
return "Saved";
}
@GetMapping(path="/all")
public @ResponseBody Iterable<User> getAllUsers() {
// This returns a JSON or XML with the users
return userRepository.findAll();
}
}
上面的示例明确指定了两个端点的 POST 和 GET 方法。默认情况下,@RequestMapping 会映射所有 HTTP 操作。 |
创建 Application 类
Spring Initializr 为应用程序创建了一个简单的类。下面的列表显示了 Initializr 为此示例创建的类(位于 src/main/java/com/example/accessingdatamysql/AccessingDataMysqlApplication.java
中):
package com.example.accessingdatamysql;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AccessingDataMysqlApplication {
public static void main(String[] args) {
SpringApplication.run(AccessingDataMysqlApplication.class, args);
}
}
对于本例,你无需修改 AccessingDataMysqlApplication
类。
Spring Initializr 会向主类添加 @SpringBootApplication
注解。@SpringBootApplication
是一个便捷注解,它包含了以下所有注解:
-
@Configuration
:将类标记为应用程序上下文的 Bean 定义来源。 -
@EnableAutoConfiguration
:Spring Boot 会尝试根据你添加的依赖自动配置你的 Spring 应用程序。 -
@ComponentScan
:告诉 Spring 扫描其他组件、配置和服务。如果未定义特定的包,则从声明此注解的类所在的包开始递归扫描。
运行应用程序
此时,你可以运行应用程序以查看你的代码实际运行。你可以通过 IDE 或命令行运行主方法。请注意,如果你从解决方案仓库克隆了项目,你的 IDE 可能会在错误的位置查找 compose.yaml
文件。你可以配置 IDE 在正确的位置查找,或者使用命令行运行应用程序。./gradlew bootRun
和 ./mvnw spring-boot:run
命令会启动应用程序并自动查找 compose.yaml
文件。
测试应用程序
应用程序运行后,你可以使用 curl
或类似工具进行测试。你有两个可以测试的 HTTP 端点:
GET localhost:8080/demo/all
:获取所有数据。POST localhost:8080/demo/add
:向数据中添加一个用户。
以下 curl
命令添加一个用户:
$ curl http://localhost:8080/demo/add -d name=First -d [email protected]
回复应如下所示:
Saved
以下命令显示所有用户:
$ curl http://localhost:8080/demo/all
回复应如下所示:
[{"id":1,"name":"First","email":"[email protected]"}]
准备构建应用程序
要打包和运行应用程序,我们需要提供一个外部 MySQL 数据库,而不是使用 Spring Boot Docker Compose 支持。为此,我们可以重用提供的 compose.yaml
文件并进行一些修改:首先,将 compose.yaml
中的 ports
条目修改为 3306:3306
。其次,添加一个 container_name
为 guide-mysql
。
完成这些步骤后,compose.yaml
文件应如下所示:
services:
mysql:
container_name: 'guide-mysql'
image: 'mysql:latest'
environment:
- 'MYSQL_DATABASE=mydatabase'
- 'MYSQL_PASSWORD=secret'
- 'MYSQL_ROOT_PASSWORD=verysecret'
- 'MYSQL_USER=myuser'
ports:
- '3306:3306'
你现在可以运行 docker compose up
来启动这个 MySQL 容器。
第三,我们需要告诉应用程序如何连接数据库。这一步之前由 Spring Boot Docker Compose 支持自动处理。为此,修改 application.properties
文件,使其变为:
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase
spring.datasource.username=myuser
spring.datasource.password=secret
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.show-sql: true
构建应用程序
本节介绍运行本指南的不同方式:
无论你选择哪种方式运行应用程序,输出都应该相同。
要运行应用程序,你可以将其打包为可执行 JAR 文件。./gradlew clean build
命令会将应用程序编译为可执行 JAR。然后可以使用 java -jar build/libs/accessing-data-mysql-0.0.1-SNAPSHOT.jar
命令运行该 JAR。
另外,如果你有可用的 Docker 环境,你可以使用 buildpacks 直接从 Maven 或 Gradle 插件创建 Docker 镜像。使用Cloud Native Buildpacks,你可以创建可在任何地方运行的 Docker 兼容镜像。Spring Boot 直接为 Maven 和 Gradle 提供了 buildpack 支持。这意味着你可以输入一个简单的命令,快速在本地运行的 Docker daemon 中获得一个合理的镜像。要使用 Cloud Native Buildpacks 创建 Docker 镜像,运行 ./gradlew bootBuildImage
命令。在启用了 Docker 环境的情况下,你可以使用 docker run --network container:guide-mysql docker.io/library/accessing-data-mysql:0.0.1-SNAPSHOT
命令运行应用程序。
--network 标志告诉 Docker 将我们的指南容器附加到外部容器正在使用的现有网络。你可以在Docker 文档中找到更多信息。 |
原生镜像支持
Spring Boot 也支持编译为原生镜像,前提是你的机器上安装了 GraalVM 发行版。要使用 Native Build Tools 通过 Gradle 创建原生镜像,首先确保你的 Gradle 构建脚本包含一个 plugins
块,其中包含 org.graalvm.buildtools.native
。
plugins { id 'org.graalvm.buildtools.native' version '0.9.28' ...
然后你可以运行 ./gradlew nativeCompile
命令来生成原生镜像。构建完成后,通过执行 build/native/nativeCompile/accessing-data-mysql
命令,你将能够以几乎瞬时启动的速度运行代码。
你也可以使用Buildpacks 创建原生镜像。通过运行 ./gradlew bootBuildImage
命令可以生成原生镜像。构建完成后,你可以使用 docker run --network container:guide-mysql docker.io/library/accessing-data-mysql:0.0.1-SNAPSHOT
命令启动应用程序。
在 Docker 中测试应用程序
如果你按照上面的 Docker 说明运行了应用程序,那么从终端或命令行执行简单的 curl
命令将不再起作用。这是因为我们的容器运行在一个无法从终端或命令行访问的Docker 网络中。要运行 curl
命令,我们可以启动一个第三个容器来运行 curl
命令,并将其附加到同一个网络中。
首先,获取一个与 MySQL 数据库和应用程序运行在同一网络上的新容器的交互式 shell。
docker run --rm --network container:guide-mysql -it alpine
接下来,在容器内的 shell 中安装 curl
:
apk add curl
最后,你可以按照测试应用程序中描述的方式运行 curl
命令。
进行一些安全更改
在生产环境中,你可能会面临 SQL 注入攻击。黑客可能会注入 DROP TABLE
或任何其他破坏性 SQL 命令。因此,作为安全实践,在向用户公开应用程序之前,你应该对数据库进行一些更改。
以下命令撤销与 Spring 应用程序关联的用户的所有权限:
mysql> revoke all on db_example.* from 'myuser'@'%';
现在 Spring 应用程序无法在数据库中执行任何操作。
应用程序必须具有一些权限,因此使用以下命令授予应用程序所需的最低权限:
mysql> grant select, insert, delete, update on db_example.* to 'myuser'@'%';
撤销所有权限并授予部分权限,使得你的 Spring 应用程序仅具有修改数据库数据的必要权限,而不能修改结构(schema)。
当你想更改数据库时:
-
重新授予权限。
-
将
spring.jpa.hibernate.ddl-auto
更改为update
。 -
重新运行你的应用程序。
然后重复此处显示的两个命令,再次使你的应用程序对生产环境安全。更好的方法是使用专用的迁移工具,例如 Flyway 或 Liquibase。
总结
恭喜!你刚刚开发了一个绑定到 MySQL 数据库并已准备好投入生产的 Spring 应用程序!
另请参阅
以下指南可能也有帮助:
想撰写新指南或为现有指南做出贡献?请查看我们的贡献指南。
所有指南的代码均采用 ASLv2 许可发布,文字内容采用知识共享署名-禁止演绎许可 (Attribution, NoDerivatives creative commons license) 发布。 |