在開發環境啟動時使用綱要和資料預先植入資料庫

在本地開發期間使用必要的資料和綱要預先植入資料庫是增強開發和測試流程的常見做法。透過模擬真實世界的場景,這種做法有助於及早發現前端問題,確保資料庫管理員和軟體工程師之間的一致性,並促進更順暢的協作。預先植入提供了諸如可靠的部署、跨環境的一致性以及早期問題檢測等優點,最終改善了整體開發流程。

在本指南中,您將學習如何

  • 使用 Docker 啟動 Postgres 容器
  • 使用 SQL 指令碼預先植入 Postgres
  • 透過將 SQL 檔案複製到 Docker 映像來預先植入 Postgres
  • 使用 JavaScript 程式碼預先植入 Postgres

搭配 Docker 使用 Postgres

Postgres 的官方 Docker 映像 提供了一種在開發機器上執行 Postgres 資料庫的簡便方法。 Postgres Docker 映像是一個預先配置的環境,封裝了 PostgreSQL 資料庫系統。它是一個自包含的單元,可以在 Docker 容器中執行。透過使用此映像,您可以快速輕鬆地設定 Postgres 執行個體,而無需手動配置。

先決條件

按照本操作指南進行操作需要具備以下先決條件

  • Docker Desktop啟動 Postgres

    使用以下步驟快速示範 Postgres

    1. 開啟終端機並執行以下命令以啟動 Postgres 容器。

      此範例將啟動一個 Postgres 容器,將埠 5432 公開到主機上,讓原生執行的應用程式可以使用密碼 mysecretpassword 連接到它。

      $ docker run -d --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword postgres
      
    2. 透過選擇容器並檢查 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
    3. 從本地系統連接到 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 資料庫執行個體正在執行,請按照以下步驟植入資料庫。

    1. 建立一個名為 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 表格中,並附上他們各自的名稱和電子郵件。 此設定形成一個基本的資料庫結構,用於儲存具有唯一電子郵件地址的使用者資訊。

    2. 植入資料庫。

      是時候使用 < 運算子將 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
    3. 執行以下 psql 命令以驗證名為 users 的表格是否已在資料庫 sampledb 中填入。

      $ docker exec -it postgres psql -h localhost -U postgres sampledb
      

      您現在可以在 psql shell 中執行 \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。

    透過繫結掛載 SQL 指令碼來預先植入資料庫

    在 Docker 中,掛載是指讓容器可以存取主機系統中的檔案或目錄。 這讓您可以在主機和容器之間共享資料或設定檔,從而實現更大的彈性和持久性。

    現在您已經學習了如何啟動 Postgres 以及如何使用 SQL 指令碼預先植入資料庫,是時候學習如何將 SQL 檔案直接掛載到 Postgres 容器的初始化目錄 (/docker-entrypoint-initdb.d) 中了。 /docker-entrypoint-initdb.d 是 PostgreSQL Docker 容器中的一個特殊目錄,用於在容器首次啟動時初始化資料庫

    在按照步驟操作之前,請確保停止任何正在執行的 Postgres 容器(以及磁碟區)以防止埠衝突

    $ docker container stop postgres
    
    1. 使用以下項目修改 seed.sql

      CREATE 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;
    2. 建立一個名為 Dockerfile 的文字檔,並複製以下內容。

      # syntax=docker/dockerfile:1
      FROM postgres:latest
      COPY seed.sql /docker-entrypoint-initdb.d/

      此 Dockerfile 將 seed.sql 指令碼直接複製到 PostgreSQL 容器的初始化目錄中。

    3. 使用 Docker Compose。

      使用 Docker Compose 可以更輕鬆地管理和部署具有植入資料庫的 PostgreSQL 容器。 此 compose.yml 檔案使用最新的 Postgres 映像定義了一個名為 db 的 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 以持久化資料庫資料,確保在容器停止時資料不會丟失。

      請務必注意,只有當您想從非容器化程式連接到資料庫時,才需要將埠映射到主機。 如果您將連接到資料庫的服務容器化,則應透過自定義橋接網路連接到資料庫。

    4. 啟動 Compose 服務。

      假設您已將 seed.sql 檔案放置在與 Dockerfile 相同的目錄中,請執行以下命令

      $ docker compose up -d --build
      
    5. 是時候驗證表格 users 是否已填入資料。

      $ docker exec -it my_postgres_db psql -h localhost -U postgres sampledb
      
      sampledb=# 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 程式碼來實現它了。

    1. 使用以下內容建立一個 .env 檔案

      POSTGRES_USER=postgres
      POSTGRES_DB_HOST=localhost
      POSTGRES_DB=sampledb
      POSTGRES_PASSWORD=mysecretpassword
      POSTGRES_PORT=5432
    2. 使用以下內容建立一個名為 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();
    3. 啟動初始設定程序

      $ node seed.js
      

      您應該會看到以下指令

      Database seeded successfully!
    4. 驗證資料庫是否已正確設定

      $ docker exec -it postgres psql -h localhost -U postgres sampledb
      
      sampledb=# SELECT * FROM todos;
      id |      task      | completed
      ----+----------------+-----------
      1 | Watch netflix  | f
      2 | Finish podcast | f
      3 | Pick up kid    | f
      (3 rows)  
      

    摘要

    在啟動時使用結構描述和資料預先設定資料庫,對於建立一致且擬真的測試環境至關重要,這有助於在開發初期識別問題,並協調前端和後端工作。本指南已提供您使用各種方法(包括 SQL 腳本、Docker 整合和 JavaScript 程式碼)進行預先設定的知識和實際步驟。