使用 MySQL 訪問資料

本指南將引導您完成建立連線到 MySQL 資料庫(而不是大多數其他指南和許多示例應用程式使用的記憶體中嵌入式資料庫)的 Spring 應用程式的過程。它使用 Spring Data JPA 訪問資料庫,但這只是許多可能的選擇之一(例如,您可以使用純 Spring JDBC)。

您將構建什麼

您將建立一個 MySQL 資料庫,構建一個 Spring 應用程式,並將其連線到新建立的資料庫。

MySQL 採用 GPL 許可,因此您隨其分發的任何程式二進位制檔案也必須使用 GPL。請參閱GNU 通用公共許可證

你需要什麼

  • 大約 15 分鐘

  • 一個喜歡的文字編輯器或 IDE

  • Java 17 或更高版本

如何完成本指南

與大多數 Spring 入門指南一樣,您可以從頭開始並完成每個步驟,或者透過檢視此倉庫中的程式碼直接跳轉到解決方案。

在您的本地環境中檢視最終結果,您可以執行以下操作之一

設定 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 檔案。此專案已配置為適合本教程中的示例。

手動初始化專案

  1. 導航到 https://start.spring.io。此服務會為您拉取應用程式所需的所有依賴項,併為您完成大部分設定。

  2. 選擇 Gradle 或 Maven 以及您想要使用的語言。本指南假設您選擇了 Java。

  3. 單擊 Dependencies 並選擇 Spring WebSpring Data JPAMySQL DriverDocker Compose SupportTestcontainers

  4. 單擊生成

  5. 下載生成的 ZIP 檔案,這是一個已根據您的選擇配置好的 Web 應用程式存檔。

如果您的 IDE 集成了 Spring Initializr,您可以從 IDE 中完成此過程。

建立 @Entity 模型

您需要建立實體模型,如以下列表(在 src/main/java/com/example/accessingdatamysql/User.java 中)所示

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;
  }
}

Hibernate 自動將實體轉換為表。

建立倉庫

您需要建立儲存使用者記錄的倉庫,如以下列表(在 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 會自動在同名 bean 中實現此倉庫介面(大小寫有變化——它被稱為 userRepository)。

建立控制器

您需要建立一個控制器來處理對應用程式的 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();
  }
}
前面的示例明確為這兩個端點指定了 POSTGET。預設情況下,@RequestMapping 對映所有 HTTP 操作。

建立應用程式類

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 https://:8080/demo/add -d name=First -d [email protected]

回覆應如下所示

Saved

以下命令顯示所有使用者

$ curl https://:8080/demo/all

回覆應如下所示

[{"id":1,"name":"First","email":"[email protected]"}]

準備構建應用程式

為了打包和執行應用程式,我們需要提供一個外部 MySQL 資料庫,而不是使用 Spring Boot Docker Compose 支援。對於此任務,我們可以重用提供的 compose.yaml 檔案並進行一些修改:首先,將 compose.yaml 中的 ports 條目修改為 3306:3306。其次,新增一個 container_nameguide-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://: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 守護程式中。要使用 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 將我們的 guide 容器連線到我們的外部容器正在使用的現有網路。您可以在 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 命令,並將其連線到同一網路。

首先,獲取一個互動式 shell 到一個與 MySQL 資料庫和應用程式在同一網路上執行的新容器中

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)進行更改所需的許可權。

當您想對資料庫進行更改時

  1. 重新授予許可權。

  2. spring.jpa.hibernate.ddl-auto 更改為 update

  3. 重新執行您的應用程式。

然後重複此處顯示的兩個命令,使您的應用程式再次適合生產使用。更好的是,使用專門的遷移工具,例如 Flyway 或 Liquibase。

總結

恭喜!您剛剛開發了一個繫結到 MySQL 資料庫並已準備好投入生產的 Spring 應用程式!

另請參閱

以下指南也可能有所幫助

想寫新指南或為現有指南做貢獻嗎?請檢視我們的貢獻指南

所有指南的程式碼均採用 ASLv2 許可,文字內容採用署名-禁止演繹知識共享許可

獲取程式碼