在開發環境中啟動時預先載入資料庫綱要與資料
在本地開發過程中,使用基礎資料和結構預載 (Pre-seeding) 資料庫是一種常見的作法,旨在改善開發與測試工作流程。透過模擬真實場景,這種做法有助於及早發現前端問題、確保資料庫管理員與軟體工程師之間的同步,並促進更順暢的協作。預載提供了諸如信心部署、跨環境的一致性以及及早檢測問題等優點,最終改善了整體開發流程。
在本指南中,您將學習如何:
- 使用 Docker 啟動一個 Postgres 容器
- 使用 SQL 指令碼預載 Postgres
- 透過將 SQL 檔案複製到 Docker 映像檔中來預載 Postgres
- 使用 JavaScript 程式碼預載 Postgres
在 Docker 中使用 Postgres
官方 Postgres Docker 映像檔提供了一種在開發機器上執行 Postgres 資料庫的便捷方式。Postgres Docker 映像檔是一個預先配置的環境,封裝了 PostgreSQL 資料庫系統。這是一個即開即用的獨立單元,可以在 Docker 容器中運作。透過使用此映像檔,您可以輕鬆快速地建立 Postgres 實例,而無需手動配置。
先決條件
若要跟隨本操作指南,需要具備以下先決條件:
啟動 Postgres
請按照以下步驟快速啟動 Postgres 示範
打開終端機並執行以下指令來啟動 Postgres 容器。
此範例將啟動一個 Postgres 容器,並將連接埠
5432暴露給主機,讓本機執行的應用程式能以密碼mysecretpassword連接到它。$ docker run -d --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword postgres選擇該容器並在 Docker Dashboard 上檢查日誌,以確認 Postgres 已啟動並執行中。
PostgreSQL Database directory appears to contain a database; Skipping initialization 2024-09-08 09:09:47.136 UTC [1] LOG: starting PostgreSQL 16.4 (Debian 16.4-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit 2024-09-08 09:09:47.137 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 2024-09-08 09:09:47.137 UTC [1] LOG: listening on IPv6 address "::", port 5432 2024-09-08 09:09:47.139 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" 2024-09-08 09:09:47.142 UTC [29] LOG: database system was shut down at 2024-09-08 09:07:09 UTC 2024-09-08 09:09:47.148 UTC [1] LOG: database system is ready to accept connections從本地系統連接到 Postgres。
psql是 PostgreSQL 的互動式 shell,用於連接到 Postgres 資料庫並開始執行 SQL 指令。假設您的本地系統已經安裝了psql工具,現在可以連接到 Postgres 資料庫。在您的本地終端機執行以下指令:$ docker exec -it postgres psql -h localhost -U postgres現在,您可以在
psql提示字元中執行任何需要的 SQL 查詢或指令。使用
\q或\quit退出 Postgres 互動式 shell。
使用 SQL 指令碼預載 Postgres 資料庫
現在您已經熟悉了 Postgres,是時候了解如何使用範例資料進行預載了。在此示範中,您將首先建立一個包含 SQL 指令的指令碼。該指令碼定義了資料庫、資料表結構並插入範例資料。隨後,您將連接到資料庫以驗證資料。
假設您已經有一個執行中的 Postgres 資料庫實例,請按照以下步驟來進行資料庫預載。
建立一個名為
seed.sql的空白檔案,並加入以下內容。CREATE DATABASE sampledb; \c sampledb CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(50), email VARCHAR(100) UNIQUE ); INSERT INTO users (name, email) VALUES ('Alpha', 'alpha@example.com'), ('Beta', 'beta@example.com'), ('Gamma', 'gamma@example.com');此 SQL 指令碼會建立一個名為
sampledb的新資料庫,連接到它,並建立一個users資料表。該資料表包含一個作為主鍵的自動遞增id、一個長度上限為 50 個字元的name欄位,以及一個長度上限為 100 個字元且唯一的email欄位。建立資料表後,
INSERT指令會將三名使用者插入到users資料表中,並附帶其姓名與電子郵件。此設置形成了用於儲存具有唯一電子郵件地址之使用者資訊的基本資料庫結構。預載資料庫。
現在是時候使用
<運算子將seed.sql的內容直接匯入到資料庫中。此指令用於針對名為sampledb的 Postgres 資料庫執行名為seed.sql的 SQL 指令碼。$ cat seed.sql | docker exec -i postgres psql -h localhost -U postgres -f-查詢執行後,您將看到以下結果
CREATE DATABASE You are now connected to database "sampledb" as user "postgres". CREATE TABLE INSERT 0 3執行以下
psql指令來驗證名為 users 的資料表是否已成功填入sampledb資料庫中。$ docker exec -it postgres psql -h localhost -U postgres sampledb您現在可以在
psqlshell 中執行\l來列出 Postgres 伺服器上的所有資料庫。sampledb=# \l List of databases Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges -----------+----------+----------+------------+------------+------------+-----------------+----------------------- postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | sampledb | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres + | | | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres + | | | | | | | postgres=CTc/postgres (4 rows)若要從 users 資料表中檢索所有資料,請輸入以下查詢
sampledb=# SELECT * FROM users; id | name | email ----+-------+------------------- 1 | Alpha | alpha@example.com 2 | Beta | beta@example.com 3 | Gamma | gamma@example.com (3 rows)使用
\q或\quit退出 Postgres 互動式 shell。
透過綁定掛載 (bind-mounting) SQL 指令碼預載資料庫
在 Docker 中,掛載是指讓主機系統的檔案或目錄可以在容器內存取。這讓您能夠在主機與容器之間共享資料或設定檔,從而實現更大的靈活性與持久性。
現在您已經學會如何啟動 Postgres 並使用 SQL 指令碼預載資料庫,是時候學習如何將 SQL 檔案直接掛載到 Postgres 容器的初始化目錄 (/docker-entrypoint-initdb.d) 中了。/docker-entrypoint-initdb.d 是 PostgreSQL Docker 容器中的一個特殊目錄,用於在容器首次啟動時進行資料庫初始化。
在執行這些步驟前,請確保停止任何執行中的 Postgres 容器(連同磁碟區),以避免連接埠衝突。
$ docker container stop postgres
使用以下項目修改
seed.sqlCREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, name VARCHAR(50), email VARCHAR(100) UNIQUE ); INSERT INTO users (name, email) VALUES ('Alpha', 'alpha@example.com'), ('Beta', 'beta@example.com'), ('Gamma', 'gamma@example.com') ON CONFLICT (email) DO NOTHING;建立一個名為
Dockerfile的文字檔案並複製以下內容。# syntax=docker/dockerfile:1 FROM postgres:latest COPY seed.sql /docker-entrypoint-initdb.d/此 Dockerfile 會將
seed.sql指令碼直接複製到 PostgreSQL 容器的初始化目錄中。使用 Docker Compose。
使用 Docker Compose 可以更輕鬆地管理和部署帶有預載資料庫的 PostgreSQL 容器。此 compose.yml 檔案定義了一個名為
db的 Postgres 服務,使用最新的 Postgres 映像檔,設定了一個名為sampledb的資料庫,以及一個使用者postgres和密碼mysecretpassword。services: db: build: context: . dockerfile: Dockerfile container_name: my_postgres_db environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: mysecretpassword POSTGRES_DB: sampledb ports: - "5432:5432" volumes: - data_sql:/var/lib/postgresql/data # Persistent data storage volumes: data_sql:它將主機上的
5432連接埠映射到容器的5432,讓您可以從容器外部存取 Postgres 資料庫。它還定義了data_sql以實現資料持久化,確保容器停止時資料不會遺失。請注意,僅在您需要從非容器化的程式連接到資料庫時,才需要進行連接埠映射。如果您將連接到資料庫的服務也容器化,則應該透過自定義橋接網路 (custom bridge network) 連接至資料庫。
啟動 Compose 服務。
假設您已經將
seed.sql檔案放置在與 Dockerfile 相同的目錄中,請執行以下指令$ docker compose up -d --build現在是時候驗證
users資料表是否已填入資料了。$ docker exec -it my_postgres_db psql -h localhost -U postgres sampledbsampledb=# SELECT * FROM users; id | name | email ----+-------+------------------- 1 | Alpha | alpha@example.com 2 | Beta | beta@example.com 3 | Gamma | gamma@example.com (3 rows) sampledb=#
使用 JavaScript 程式碼預載資料庫
既然您已經學會了如何透過 SQL 指令碼、掛載磁碟區等多種方法預載資料庫,現在是時候嘗試使用 JavaScript 程式碼來達成目標。
建立一個包含以下內容的 .env 檔案
POSTGRES_USER=postgres POSTGRES_DB_HOST=localhost POSTGRES_DB=sampledb POSTGRES_PASSWORD=mysecretpassword POSTGRES_PORT=5432建立一個名為 seed.js 的新 JavaScript 檔案,並包含以下內容
以下 JavaScript 程式碼匯入了
dotenv套件,用於從.env檔案載入環境變數。.config()方法會讀取.env檔案並將環境變數設定為process.env物件的屬性。這讓您能夠將資料庫憑證等敏感資訊安全地儲存在程式碼之外。接著,它從 pg 函式庫建立了一個新的 Pool 實例,該實例提供了用於高效資料庫互動的連接池。定義了
seedData函式以執行資料庫預載操作。在指令碼末尾呼叫它以啟動預載流程。try...catch...finally 區塊則用於錯誤處理。require('dotenv').config(); // Load environment variables from .env file const { Pool } = require('pg'); // Create a new pool using environment variables const pool = new Pool({ user: process.env.POSTGRES_USER, host: process.env.POSTGRES_DB_HOST, database: process.env.POSTGRES_DB, port: process.env.POSTGRES_PORT, password: process.env.POSTGRES_PASSWORD, }); const seedData = async () => { try { // Drop the table if it already exists (optional) await pool.query(`DROP TABLE IF EXISTS todos;`); // Create the table with the correct structure await pool.query(` CREATE TABLE todos ( id SERIAL PRIMARY KEY, task VARCHAR(255) NOT NULL, completed BOOLEAN DEFAULT false ); ` ); // Insert seed data await pool.query(` INSERT INTO todos (task, completed) VALUES ('Watch netflix', false), ('Finish podcast', false), ('Pick up kid', false); `); console.log('Database seeded successfully!'); } catch (err) { console.error('Error seeding the database', err); } finally { pool.end(); } }; // Call the seedData function to run the script seedData();啟動預載流程
$ node seed.js您應該會看到以下指令
Database seeded successfully!驗證資料庫是否已正確預載
$ docker exec -it postgres psql -h localhost -U postgres sampledbsampledb=# SELECT * FROM todos; id | task | completed ----+----------------+----------- 1 | Watch netflix | f 2 | Finish podcast | f 3 | Pick up kid | f (3 rows)
重點回顧
在啟動時使用結構與資料預載資料庫,對於建立一致且真實的測試環境至關重要,這有助於在開發初期識別問題,並整合前後端工作。本指南已讓您具備相關知識與實作步驟,透過包括 SQL 指令碼、Docker 整合與 JavaScript 程式碼等多種方法達成預載目標。