การย้ายฐานข้อมูลด้วย go
เมื่อทำงานกับฐานข้อมูล การโยกย้ายสคีมาเป็นงานสำคัญอย่างหนึ่งที่เรามักจะต้องทำตลอดอายุการใช้งานของแอปพลิเคชันเพื่อปรับให้เข้ากับความต้องการทางธุรกิจใหม่
ในบทความนี้ เราจะเรียนรู้วิธีการเขียนและเรียกใช้การโยกย้ายสคีมาฐานข้อมูลใน Go โดยใช้ไลบรารี golang-migrate
ข้อกำหนดเบื้องต้น
ข้อกำหนดสำหรับบทความนี้คือ คุณต้องติดตั้ง Go บนคอมพิวเตอร์ของคุณ และได้ทำตามบทความ ติดตั้งและใช้ Docker + Postgres มาก่อน
ติดตั้ง golang-migrate
Golang-migrate ทำงานร่วมกับเครื่องมือฐานข้อมูลต่างๆ เช่น postgres, mysql, mongo, cockroach ฯลฯ เปิด เอกสาร CLI นี้เพื่อดูวิธีการติดตั้ง
การติดตั้ง golang-migrate บน Windows
ติดตั้ง scoop
Scoop เป็นโปรแกรมจัดการแพ็คเกจบรรทัดคำสั่งสำหรับ Windows ซึ่งช่วยให้ติดตั้งและใช้โปรแกรมและเครื่องมือทั่วไปได้ง่ายขึ้น
ตรวจสอบให้แน่ใจว่าได้ติดตั้ง PowerShell และ .NET Framework 4.5 (หรือใหม่กว่า) แล้ว จากนั้นเรียกใช้:
iwr -useb get.scoop.sh | iex
ตอนนี้คุณได้ติดตั้ง Scoop บนระบบ windows ของคุณแล้ว เราสามารถดำเนินการต่อไปกับงานหลักของเรา เช่น golang-migrate
ดาวน์โหลดไบนารีที่สร้างไว้ล่วงหน้า (Windows, MacOS หรือ Linux)
curl -L https://github.com/golang-migrate/migrate/releases/download/$version/migrate.$platform-amd64.tar.gz | tar xvz
ตอนนี้เราได้ดาวน์โหลด scoop และไลบรารี่ที่สร้างไว้ล่วงหน้าสำหรับ golang-migrate แล้ว เราจะดำเนินการติดตั้งโดยใช้คำสั่งง่ายๆ นี้
scoop install migrate
Create a new migration
ตกลง ตอนนี้ฉันกำลังจะสร้างโฟลเดอร์ใหม่สำหรับโครงการ Simple Bank ของเรา และข้างใน ฉันจะสร้างโฟลเดอร์ใหม่ db/migration เพื่อเก็บไฟล์การย้ายข้อมูลทั้งหมดของเรา
cd Go/src/
mkdir simple_bank
cd simple_bank
mkdir -p db/migration
จากนั้น มาสร้างไฟล์การโยกย้ายครั้งแรกเพื่อเริ่มต้นสคีมาฐานข้อมูลของ Simple Bank
เริ่มด้วย migrate create จากนั้นนามสกุลของไฟล์จะเป็น sql และไดเร็กทอรีที่จะจัดเก็บก็ db/migration ด้วยคำสั่ง
migrate create -ext sql -dir db/migration -seq init_schema
เราใช้แฟล็ก -seq เพื่อสร้างหมายเลขเวอร์ชันตามลำดับสำหรับไฟล์การย้ายข้อมูล และสุดท้ายชื่อการโยกย้ายซึ่ง init_schema ในกรณีนี้
อย่างที่คุณเห็น มีการสร้างไฟล์การโยกย้าย 2 ไฟล์สำหรับเรา ทั้งคู่มีเวอร์ชัน 1 อยู่ในคำนำหน้าของชื่อไฟล์ แต่ส่วนต่อท้ายต่างกัน: 1 ไฟล์เป็น up และอีกไฟล์หนึ่งคือ down. ทำไม?
การโยกย้ายขึ้น/ลง
โดยพื้นฐานแล้วมันเป็นแนวทางปฏิบัติที่ดีที่สุดเมื่อเขียนการย้ายฐานข้อมูล สคริปต์ up ถูกเรียกใช้เพื่อทำการเปลี่ยนแปลงไปข้างหน้ากับสคีมา และสคริปต์ down จะทำงานถ้าเราต้องการย้อนกลับการเปลี่ยนแปลงที่ทำโดยสคริปต์ up
ดังนั้นเมื่อเรารัน migrate up คำสั่ง up ไฟล์สคริปต์ภายในโฟลเดอร์ db/migration จะถูกรันตามลำดับของเวอร์ชันนำหน้า
ในทางกลับกัน เมื่อเรารัน migrate down คำสั่ง ไฟล์ down-script ภายใน db/migration โฟลเดอร์จะถูกรันตามลำดับโดยกลับกันของเวอร์ชันนำหน้า
เรามาเปิด simple_bank.sql ไฟล์ที่เราสร้างขึ้นจากบทความ ติดตั้งและใช้ Docker + Postgres โดยจะคัดลอกเนื้อหาทั้งหมดของไฟล์นี้แล้ววางลงในไฟล์ init_schema.up.sql
CREATE TABLE "accounts" (
"id" bigserial PRIMARY KEY,
"owner" varchar NOT NULL,
"balance" bigint NOT NULL,
"currency" varchar NOT NULL,
"created_at" timestamptz NOT NULL DEFAULT (now())
);
CREATE TABLE "entries" (
"id" bigserial PRIMARY KEY,
"account_id" bigint NOT NULL,
"amount" bigint NOT NULL,
"created_at" timestamptz NOT NULL DEFAULT (now())
);
CREATE TABLE "transfers" (
"id" bigserial PRIMARY KEY,
"from_account_id" bigint NOT NULL,
"to_account_id" bigint NOT NULL,
"amount" bigint NOT NULL,
"created_at" timestamptz NOT NULL DEFAULT (now())
);
ALTER TABLE "entries" ADD FOREIGN KEY ("account_id") REFERENCES "accounts" ("id");
ALTER TABLE "transfers" ADD FOREIGN KEY ("from_account_id") REFERENCES "accounts" ("id");
ALTER TABLE "transfers" ADD FOREIGN KEY ("to_account_id") REFERENCES "accounts" ("id");
CREATE INDEX ON "accounts" ("owner");
CREATE INDEX ON "entries" ("account_id");
CREATE INDEX ON "transfers" ("from_account_id");
CREATE INDEX ON "transfers" ("to_account_id");
CREATE INDEX ON "transfers" ("from_account_id", "to_account_id");
COMMENT ON COLUMN "entries"."amount" IS 'can be negative or positive';
COMMENT ON COLUMN "transfers"."amount" IS 'must be positive';
สำหรับไฟล์ init_schema.down.sql เราควรคืนค่าการเปลี่ยนแปลงที่ทำโดยสคริปต์ up ในกรณีนี้ สคริปต์ up จะสร้าง 3 ตาราง คือ: accounts, , transfers และ entries ดังนั้นสคริปต์ down ควรลบทั้งหมด เราใช้ DROP TABLE แบบสอบถามเพื่อจุดประสงค์นี้
DROP TABLE IF EXISTS entries;
DROP TABLE IF EXISTS transfers;
DROP TABLE IF EXISTS accounts;
ที่นี่เราวางตาราง entries และ transfers ก่อนที่จะวางตาราง accounts เนื่องจากมีข้อจำกัดของคีย์ต่างประเทศ entries และ transfers ที่อ้างอิงบันทึก accounts
ตกลง ตอนนี้สคริปต์การย้ายข้อมูลของเราพร้อมแล้ว ลองเรียกใช้พวกเขา
ตรวจสอบสถานะคอนเทนเนอร์ของ postgres
แต่ก่อนหน้านั้นเราควรตรวจสอบว่าคอนเทนเนอร์ postgres ของเรายังทำงานอยู่หรือไม่:
docker ps
ฉันจะแสดงคำสั่ง docker เพิ่มเติมเพื่อทำงานกับคอนเทนเนอร์ หากเราต้องการหยุดคอนเทนเนอร์ที่ทำงานอยู่ เราจะใช้ docker stop กับชื่อคอนเทนเนอร์หรือ ID
docker stop postgres12
หลังจากนี้ถ้าเรารัน docker ps เราจะไม่เห็นคอนเทนเนอร์ postgres อีกต่อไปเพราะไม่ได้ทำงาน ในการแสดงรายการคอนเทนเนอร์ทั้งหมด โดยไม่คำนึงถึงสถานะการทำงาน เราสามารถเรียกใช้:
docker ps -a
ตอนนี้เราเห็น postgres คอนเทนเนอร์ของเราพร้อมสถานะ Exited
หากต้องการเปิดใช้งานอีกครั้ง เราเพียงแค่ต้องเรียกใช้: docker star tและ ส่งต่อชื่อคอนเทนเนอร์หรือ ID
docker start postgres12
และตอนนี้คอนเทนเนอร์ postgres12 เริ่มทำงานแล้ว
เข้าถึง shell คอนเทนเนอร์ของ postgres
เราสามารถเข้าถึงเปลือกของมันได้ด้วยคำสั่ง docker exec เนื่องจากเราใช้ postgres alpine image เราไม่มี shell /bin/bash เหมือนใน ubuntu ดังนั้นเราจึงใช้ shell /bin/sh แทน:
docker exec -it postgres12 /bin/sh
ภายในเชลล์ เราสามารถเข้าถึงคำสั่ง linux มาตรฐานทั้งหมดได้ เช่น คำสั่ง ls จะแสดง List ของ File และ Directory ใน Path ที่ใช้งานอยู่
ls -l
และเนื่องจากนี่คือคอนเทนเนอร์ postgres มันจึงให้คำสั่ง CLI บางอย่างแก่เราในการโต้ตอบกับเซิร์ฟเวอร์ postgres โดยตรงจาก shell
Create/drop ฐานข้อมูลภายในคอนเทนเนอร์ postgres
เราต้องสร้างฐานข้อมูลก่อนจึงจะสามารถเรียกใช้การโยกย้ายครั้งแรกได้
ให้เรียกใช้คำสั่ง createdb ภายในเชลล์ของคอนเทนเนอร์ postgres เพื่อสร้างฐานข้อมูลใหม่สำหรับ Simple Bank ของเรา:
createdb --username=root --owner=root simple_bank
- เราใช้ตัวเลือก –username เพื่อบอกว่าเรากำลังเชื่อมต่อในฐานะ root ผู้ใช้
- และตัวเลือก –owner ที่จะบอกว่าฐานข้อมูลที่เราจะสร้างจะเป็นของ root ผู้ใช้ด้วยเช่นกัน
- อาร์กิวเมนต์สุดท้ายคือชื่อฐานข้อมูล simple_bank
ตกลง เราสร้างฐานข้อมูลแล้ว และสามารถเข้าถึงคอนโซลได้ด้วยคำสั่ง psql
นอกจากนี้เรายังสามารถลบฐานข้อมูลโดยใช้ dropdb คำสั่งและส่งต่อในชื่อของฐานข้อมูล
dropdb simple_bank
เราใช้คำสั่ง exit เพื่อออกจาก shell คอนเทนเนอร์
exit
Create/drop ฐานข้อมูลนอกคอนเทนเนอร์ postgres
ตอนนี้จากภายนอกคอนเทนเนอร์ เราสามารถเรียกใช้ createdb ด้วยคำสั่ง docker exec ได้โดยตรง
docker exec -it postgres12 createdb --username=root --owner=root simple_bank
และเข้าถึงคอนโซลฐานข้อมูลโดยไม่ต้องผ่าน shell คอนเทนเนอร์
docker exec -it postgres12 psql -U root simple_bank
exit
หยุดคอนเทนเนอร์ postgres ปัจจุบัน
docker stop postgres12
คอนเทนเนอร์หยุดทำงาน ฉันจะลบมันออกให้หมดโดยใช้คำสั่ง docker rm
docker rm postgres12
เราจะไม่เห็นคอนเทนเนอร์ postgres อีกต่อไปเพราะไม่ได้ทำงาน ตรวจสอบได้จากคำสั่ง
docker ps -a
เขียน Makefile
ตอนนี้ฉันกำลังจะสร้าง Makefile ในโครงการของเรา จากนั้นเพิ่มคำสั่ง createdb เพื่อสร้างฐานข้อมูลธนาคารอย่างง่าย และคำสั่ง dropdb เพื่อลบมัน ก่อนอื่น ต้องติดตั้ง Make และ ทดสอบ ตามบทความ การใช้ Makefile ภาษา GO มาก่อน
เมื่อทำงานในทีม คำสั่งเหล่านี้จะเป็นประโยชน์สำหรับเพื่อนร่วมทีมของคุณในการตั้งค่าโปรเจ็กต์บนเครื่องในพื้นที่ของตนเพื่อการพัฒนาได้อย่างง่ายดาย
มาเพิ่มคำสั่งที่เราใช้ในการเริ่มคอนเทนเนอร์ postgres ในการบรรยายครั้งก่อนไปยัง Makefile ด้วย
สร้างไฟล์ Makefile เขียนโค้ดดังนี้
postgres:
docker run --name postgres12 -p 5432:5432 -e POSTGRES_USER=root -e POSTGRES_PASSWORD=secret -d postgres:12-alpine
createdb:
docker exec -it postgres12 createdb --username=root --owner=root simple_bank
dropdb:
docker exec -it postgres12 dropdb simple_bank
.PHONY: postgres createdb dropdb
ทดสอบใช้คำสั่ง
make postgres
คอนเทนเนอร์ postgres ใหม่จะเริ่มต้นขึ้น และทดลองใช้คำสั่ง make createdb เพื่อสร้างฐานข้อมูล simple_bank
make createdb
ตรวจสอบการสร้าง ฐานข้อมูล simple_bank ได้จากคำสั่ง
docker ps
ดูฐานข้อมูลด้วย TablePlus
เราได้สร้างฐานข้อมูลแล้ว มาเชื่อมต่อกับมันโดยใช้ TablePlus
การเชื่อมต่อที่เราตั้งค่าในครั้งก่อน จะนำเราไปยังฐานข้อมูล root เราสามารถคลิกที่ไอคอนฐานข้อมูลเพื่อเปิดฐานข้อมูล simple_bank ใหม่ของเรา
คุณสามารถดู 2 ฐานข้อมูล ได้ที่นี่: root และ simple_bank และ สำหรับตอนนี้ฐานข้อมูล simple_bank ว่างเปล่า
เรียกใช้การโยกย้าย migration
กลับไปที่เทอร์มินัล เข้าไปในโฟลเดอร์โครงการ Simple Bank ของเรา แล้วเรียกใช้การย้ายข้อมูลครั้งแรก
เริ่มด้วย migrate จากนั้นเราใช้ – path ตัวเลือกเพื่อระบุโฟลเดอร์ที่มีไฟล์การโยกย้ายของเรา ซึ่งก็คือ db/migration
migrate -path db/migration -database "postgresql://root:secret@localhost:5432/simple_bank" -verbose up
ตัวเลือกนี้ -database ใช้เพื่อระบุ URL ไปยังเซิร์ฟเวอร์ฐานข้อมูล
- เราใช้ postgres ดังนั้นชื่อไดรเวอร์คือ postgresql
- จากนั้นชื่อผู้ใช้คือ root
- รหัสผ่านคือ secret
- ที่อยู่คือ localhost พอร์ต 5432
- และชื่อฐานข้อมูลคือ simple_bank.
เราใช้ตัวเลือก -verbose เพื่อขอให้โยกย้ายเพื่อพิมพ์การบันทึกแบบละเอียด
และสุดท้ายเราใช้อาร์กิวเมนต์ up เพื่อบอกให้ migrate รันคำสั่ง migrate up
เรามีข้อผิดพลาด: error: pq: SSL is not enabled on the server เพราะไม่ได้เปิดใช้งาน SSL บนเซิร์ฟเวอร์ นั่นเป็นเพราะคอนเทนเนอร์ postgres ของเราไม่ได้เปิดใช้งาน SSL เป็นค่าเริ่มต้น
ดังนั้นเราควรเพิ่มพารามิเตอร์ sslmode=disable ลงใน URL ฐานข้อมูล ตอนนี้รันคำสั่งนี้:
migrate -path db/migration -database "postgresql://root:secret@localhost:5432/simple_bank?sslmode=disable" -verbose up
และการโยกย้ายก็สำเร็จ!
หากเรารีเฟรชฐานข้อมูล simple_bank ใน TablePlus เราจะเห็นตาราง 4 ตาราง คือ : accounts, entries, , transfers และ schema_migrations
ตาราง schema_migrations จะจัดเก็บเวอร์ชันการโยกย้ายที่ใช้ล่าสุด ซึ่งในกรณีของเราคือเวอร์ชัน 1 เนื่องจากเราเรียกใช้ไฟล์การย้ายข้อมูลเพียงไฟล์เดียว
คอลัมน์ dirty นี้จะบอกเราว่าการโยกย้ายครั้งล่าสุดล้มเหลวหรือไม่ หากล้มเหลว เราต้องแก้ไขปัญหาด้วยตนเองเพื่อให้สถานะฐานข้อมูลสะอาดก่อนที่จะพยายามเรียกใช้เวอร์ชันการโยกย้ายอื่นๆ
เพิ่มการโยกย้ายขึ้น/ลงไปยัง Makefile
ตกลงตอนนี้ฉันจะเพิ่ม migrateup และ migratedown ในคำสั่ง Makefile:
postgres:
docker run --name postgres12 -p 5432:5432 -e POSTGRES_USER=root -e POSTGRES_PASSWORD=secret -d postgres:12-alpine
createdb:
docker exec -it postgres12 createdb --username=root --owner=root simple_bank
dropdb:
docker exec -it postgres12 dropdb simple_bank
migrateup:
migrate -path db/migration -database "postgresql://root:secret@localhost:5432/simple_bank?sslmode=disable" -verbose up
migratedown:
migrate -path db/migration -database "postgresql://root:secret@localhost:5432/simple_bank?sslmode=disable" -verbose down
.PHONY: postgres createdb dropdb migrateup migratedown
ใช้คำสั่ง make migratedown
make migratedown
และกลับไปที่ TablePlus และรีเฟรช ตารางทั้งหมดจะหายไป ยกเว้นตาราง schema_migrations
ใช้คำสั่ง make migrateup
make migrateup
จากนั้นรีเฟรช TablePlus ตารางทั้งหมดจะกลับมาอีกครั้ง
credit : https://dev.to/techschoolguru/