後端工程師或 SRE (Site Reliability Engineer) 常常需要備份資料庫數據,以確保硬碟損壞時,還有數據還可以還原。除了手動備份資料外,如果可以寫排程 (Scheduler) 定時備份資料的話,不但省力,還不怕忘記備份。讓我們來看看,如何用 Spring Boot 備份和還原資料庫數據。
Table of Contents
備份 (Backup)
資料庫的備份,主要是利用 mysqldump 指令來實現。mysqldump 會將資料庫數據匯出成 .sql 格式的檔案。它有很多的參數,下面是最基本的使用方式:
% mysqldump -uroot -p123456 --add-drop-table --database Example -r example.sql
- -uroot:root 是 MySQL 的登入帳號。和 -u 之間沒有空格。
- -p123456:123456 是 MySQL 的登入密碼。和 -p 之間沒有空格。
- –add-drop-table:在匯出的 .sql 檔中,加入
DROP TABLE
,這樣方便匯入。 - –database:Example 是要匯出的資料庫名稱。
- -r example.sql:example.sql 是匯出的目標檔案。
可以先在命令列上,測試指令是否正確。確定指令正確無誤後,我們就可以開始用 Spring Boot 來執行指令。
新增 DatabaseUtil
,在裡面我們實作 backup()
方法。它主要是利用 Runtime.getRuntime().exec()
來執行命令列指令。
public final class DatabaseUtil { public static boolean backup(String dbUsername, String dbPassword, String dbName, String outputFile) throws IOException, InterruptedException { String command = String.format("mysqldump -u%s -p%s --add-drop-table --databases %s -r %s", dbUsername, dbPassword, dbName, outputFile); Process process = Runtime.getRuntime().exec(command); int processComplete = process.waitFor(); return processComplete == 0; } }
然後,我們可以實作 RestController 來讓前端發起被備份工作,或是實作 Scheduler 排成來定時發起備份工作。
還原 (Restore)
和備份一樣,還原也是用指令實現。用 mysql 指令就可以還原,使用方式如下:
% mysql -uroot -p123456 -e "source example.sql"
- -e command, –execute=command:這個 option 是指執行後面的 SQL statement。
- source example.sql:這個 SQL statement 是指執行 example.sql 裡面的 SQL statements。
所以說,匯入數據其實就是執行 .sql 檔裡面的所有 SQL statement。這也是因為我們在匯出時,要加上 --add-drop-table
的原因。不然,在執行 .sql 檔時,裡面會有 CREATE TABLE
,因為 table 已經存在,所以這個 CREATE TABLE
statement 會失敗。再不然,就是在執行前,先手動刪除 table。當然,最方便的方式還是加上 --add-drop-table
。
在 DatabaseUtil
裡,加上 restore()
方法。也是用 Runtime.getRuntime().exec()
來執行指令。不過,因為 source example.sql
是一個參數,不能將指令串好成一個字串去執行。要改用將指令分成陣列的方式去執行才行。
public final class DatabaseUtil { public static boolean restore(String dbUsername, String dbPassword, String dbName, String sourceFile) throws IOException, InterruptedException { String[] command = new String[]{ "mysql", "-u" + dbUsername, "-p" + dbPassword, "-e", " source " + sourceFile, dbName }; Process runtimeProcess = Runtime.getRuntime().exec(command); int processComplete = runtimeProcess.waitFor(); return processComplete == 0; } }
最後,實作 RestController 來讓前端發起還原的工作吧。