【Spring Boot】第8.1課-準備 MySQL 資料庫與認識 Spring Data JPA


https://unsplash.com/photos/LmyPLbbUWhA

在第 7 課系列,我們了解如何在 Spring Boot 操作 MongoDB。而第 8 課系列要學習的是操作 MySQL 資料庫,它是一種關聯式資料庫,具有嚴謹的性質。除了是一般課程常見的題材,幾乎也是職缺的必備要求。

本文會啟動 MySQL 的服務,並在 Spring Boot 專案中配置各種參數,確認可以連線上。最後介紹「Spring Data JPA」這套框架,了解它的由來。

一、準備 MySQL 環境

(一)Docker 容器

讀者可在命令列(command line)環境下,透過 Docker 指令啟動 MySQL 的服務。

docker run -d --name "MySQL_8.2.0" -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mongo:8.2.0

以上取用的 MySQL 版本為 8.2.0。容器取名為「MySQL_8.2.0」,運行在 3306 的 port 號上。而 root 帳號的密碼設為「123456」。

其他版本可參考 Docker Hub。關於 Docker 的操作,本文將不詳細介紹。

(二)圖形化介面工具

為了直接查詢資料庫中的資料,讀者可安裝圖形化介面(GUI)工具。本文選擇「Workbench」。

開啟 GUI 後,點擊「MySQL Connections」字樣旁邊的「+」號,會出現資料庫連線設定的視窗。若讀者想存取不同伺服器上的資料庫,就能在這裡建立多個需要的連線。

mysql-workbench-setup-new-connection

在上圖中,「Connection name」欄位是為這個連線命名,方便我們在 GUI 辨識。其他欄位則填寫資料庫的位址、port 號與帳號。至於密碼,需點擊「Store in Vault ...」後,在小視窗輸入。

最後按下「OK」,即可建立連線。

(三)建立資料庫

按下 GUI 上方的「SQL」按鈕,可開啟查詢視窗。下圖撰寫了兩句語法,第一句是建立名稱為「school」的資料庫,第二句是切換過去。

mysql-workbench-use-query-to-create-database

按下閃電符號後,就會執行視窗中的全部指令。以上這些操作,其實不透過指令,也能藉由 GUI 完成,讀者可自行探索。

二、準備程式專案

(一)添加依賴

本節讓我們在 Spring Boot 專案中串接資料庫。請在 pom.xml 檔案添加「Spring Data JPA」與「MySQL Connector」的依賴。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

如果讀者有用過早期的 JDBC(Java Database Connectivity),應該對存取資料庫的程式流程還留有一點印象,大致包含以下步驟:

  1. 建立資料庫連線。
  2. 撰寫原生 SQL 語法,產生「Statement」物件。
  3. 將裝有查詢結果的「Result Set」物件,轉換成商業邏輯要用的程式物件。
  4. 釋放資源。

由於太過繁瑣,於是「Spring Data JPA」這套框架封裝了此過程,讓開發者能更輕鬆地存取資料庫。

事實上,Spring Data JPA 或 JDBC 並非只能用來存取 MySQL 而已。其他常見的關聯式資料庫,如 SQL Server、Oracle 與 PostgreSQL 也都支援,因為這些資料庫廠商提供了「驅動程式」(Driver)。

(二)配置參數

請在專案的「src\main\resources」路徑下,找到一個叫做「application.properties」的檔案,並在裡頭配置數個參數。

# 資料來源
spring.datasource.url=jdbc:mysql://localhost:3306/school
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# 資料庫資訊
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.properties.hibernate.dialect_version=8
spring.jpa.properties.hibernate.dialect.storage_engine=innodb

# 資料表配置
spring.jpa.hibernate.ddl-auto=update

# 是否在 console 印出 SQL 指令並對其格式化
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true

首先提供資料來源(data source),包含 MySQL 的位址、帳密,以及驅動程式的 package 路徑。此處連線到叫做「school」的資料庫。而驅動程式是來自於前面添加的「mysql-connector-j」依賴。

若讀者未來要在 Docker 容器中運行 Spring Boot,可能需將網域從「localhost」改為「host.docker.internal」,如下:

spring.datasource.url=jdbc:mysql://host.docker.internal:3306/school

Spring Data JPA 預設是先封裝另一個叫做「Hibernate」的框架,再由它封裝 JDBC。Hibernate 提供了與資料庫互動的強大功能,本身可獨立使用。Spring Data JPA 只是將其整合進來,讓我們容易應用於 Spring Boot 程式中罷了。

為了讓 Hibernate 根據不同的資料庫執行正確的指令,我們需要提供代表資料庫種類的「方言」,以及資料庫的版本與儲存引擎。此處提供 MySQLDialect 方言、版本 8 與 InnoDB 儲存引擎。

Spring Data JPA 允許我們在程式中直接定義資料表(table),並可在啟動 Spring Boot 程式時,控制 Hibernate 自動去配置 table。有以下幾個選項。

  • create:重新建立 table,故原有的資料會遺失,請慎用。
  • create-drop:同 create,且程式關閉後,會自動刪除 table。
  • update:會根據我們的定義去更新 table,補上新欄位,但不刪除舊欄位。
  • validate:會檢查 table 是否缺少我們在程式中定義的欄位。若有,則拋出例外,具有提醒的效果。
  • none:不做自動配置。

最後請啟動 Spring Boot。若 console 沒有出現 exception 訊息,代表有成功連線到 MySQL 的服務。

這份叫做 application.properties 的檔案,在「【Spring Boot】第13課-在 application.properties 配置檔提供參數」文章會專門介紹。讀者只要知道 library 會從中讀取指定名稱的參數即可。

三、定義資料的實體類別

在資料庫中,每個 table 在程式中都對應到一個實體(entity)類別。比方說想儲存學生資料,那就可以設計對應的實體類別,如下:

該類別叫做「Student」,包含 id、名字與年級,共 3 個欄位。

使用 @Entity 注解,代表它是要儲存到資料庫的實體類別。而 @Table 注解,則設定它在資料庫中,要對應到叫做「student」的 table 。

在 id 欄位,冠上了 @Id 注解,代表它是 table 中的主鍵(Primary Key,PK)。而 @GeneratedValue 注解,則設定主鍵值的產生方式。由於 MySQL 支援自增長(auto increment)的 id,因此選擇 GenerationType.IDENTITY

重新啟動 Spring Boot,讀者便可在 GUI 中看到建立好的 table 了。

mysql-workbench-describe-table-with-few-fields

四、Spring Data JPA 介紹

在本文第二節,我們添加了「Spring Data JPA」的依賴,本節將進一步介紹。

(一)JDBC 使用範例

當 JDBC 結合對應的驅動程式,便可存取 MySQL 等關聯式資料庫,以下為示意程式:

由於使用程式碼操作的過程太繁瑣,因此有些框架將它封裝起來。

(二)物件關聯對映(ORM)

從示意程式中,直接使用 JDBC 的其中一個環節,包含將商業邏輯物件與資料庫的資料互相轉換。比方說查詢時,需取出結果中的每個欄位值,在程式中建立出物件;插入或更新時,則需拼湊出 SQL 語法。

因此,「物件關聯對映」(Object-Relational Mapping,ORM)這項技術出現了,為的就是封裝這段轉換過程。其中 Hibernate、MyBatis、EclipseLink 等 ORM 框架就有提供這項功能,可單獨引進使用。

這些 ORM 框架,並不是只有提供物件和資料之間的轉換功能而已,它們本身就是對整個使用 JDBC 的過程進行封裝。

(三)Spring Data JPA 框架

Spring 為了讓我們在程式中更容易使用這些存取資料庫的技術,於是推出 Spring Data JPA 這項產品,將 ORM 框架整合進來。但它只整合那些有實現 JPA(Java Persistance API)規範的 ORM 框架,如 Hibernate、EclipseLink。

所謂的 JPA 規範,其實我們在本文第三節建立 Student 類別時已經接觸到了,那就是「jakarta.persistence」套件下的 @Entity@Table@Id 等注解。後續文章也會使用 @Column 注解,進行欄位的細部設定;或透過 @OneToOne注解,設計一對一關聯。

Spring Data JPA 預設採用 Hibernate 框架來存取資料庫。讓我們在操作上,能夠以 Java 程式語言為導向,不再依賴於不同資料庫的原生 SQL 語法。

本文的完成專案:
https://github.com/ntub46010/SpringBootTutorial/tree/Ch8-1

上一篇:【Spring Boot】第7.3課-在 MongoRepository 定義查詢條件與排序方式

下一篇:【Spring Boot】第8.2課-使用 JPA 設計實體類別與 MySQL 資料表欄位

留言