Hệ thống kiểm soát phiên bản và đặc biệt là Git là những công cụ thiết yếu để theo dõi các thay đổi mã, cộng tác với nhóm của bạn và đảm bảo tính ổn định của cơ sở mã của bạn. Mặc dù Git được thiết kế chủ yếu cho mã nguồn nhưng bạn cũng có thể sử dụng nó kết hợp với cơ sở dữ liệu MySQL để kiểm soát phiên bản và quản lý thay đổi lược đồ.
Trong bài viết này, chúng ta sẽ khám phá cách tích hợp Git với MySQL để kiểm soát phiên bản bằng cách sử dụng móc Git, với các ví dụ cụ thể ở định dạng hướng dẫn. Tất cả các tập lệnh được đưa ra trong danh sách đều có đầy đủ chức năng và đầy đủ. Bạn có thể tái tạo chúng một cách tuần tự trong môi trường thử nghiệm của mình.
Trước hết, hãy tạo cơ sở dữ liệu và người dùng thử nghiệm:
create database testdb_remote; create user 'user_remote'@'localhost' identified WITH mysql_native_password by 'remote123'; grant all on testdb_remote.* to 'user_remote'@'localhost';
Tiếp theo, chúng ta sẽ tạo một kho lưu trữ từ xa. Đây có thể là một kho lưu trữ trên bất kỳ máy chủ từ xa nào, nhưng để đơn giản, chúng tôi sẽ tạo nó cục bộ. Để thuận tiện cho việc thực thi lệnh, tôi sử dụng git bash. Máy cục bộ của tôi đã có thư mục git nên tôi sử dụng nó:
cd /c/git mkdir testdb.remote cd testdb.remote git init --bare
Và tạo một kho lưu trữ cục bộ dưới dạng bản sao của kho lưu trữ từ xa:
cd /c/git git clone /c/git/testdb.remote testdb.local cd testdb.local git ls-files
Không có tập tin nào trong kho lưu trữ; hãy tạo một cái và đẩy các thay đổi của chúng tôi sang repo từ xa:
echo "Test DB repo" > readme.md git status git add . git commit -m "1st commit" git push
Hãy kiểm tra nội dung của kho lưu trữ từ xa:
cd /c/git/testdb.remote git ls-tree --full-tree -r HEAD
Có một thư mục hooks trong kho lưu trữ từ xa, chứa một số tệp có ví dụ:
ls -1 /c/git/testdb.remote/hooks
Móc là các tập lệnh được thực thi khi các sự kiện cụ thể xảy ra. Git có hook phía máy khách và phía máy chủ. Các hook phía máy khách được kích hoạt bởi các hoạt động như cam kết và hợp nhất. Các hook phía máy chủ chạy trên các hoạt động mạng như nhận các cam kết được đẩy. Móc được mô tả chi tiết ở đây . Có nhiều lựa chọn khác nhau để triển khai logic; Tôi sẽ đưa ra một ví dụ về việc sử dụng hook phía máy chủ sau khi nhận .
Trong thư mục hooks, chúng ta cần tạo một tệp có tên "post-receive", đây là tập lệnh bash thông thường:
#!/bin/sh while read oval nval ref do echo List of files changed in the commit: git diff --name-only $oval $nval done
Đoạn script trên sẽ được thực thi trên máy chủ bất cứ khi nào quá trình đẩy được hoàn thành thành công và sẽ xuất ra danh sách các tệp đã sửa đổi. Hãy kiểm tra xem nó hoạt động như thế nào bằng cách thêm một dòng vào readme.md và đẩy các thay đổi vào kho lưu trữ từ xa:
cd /c/git/testdb.local echo "New line" >> readme.md git add . git commit -m "Line added" git push
Bạn có thể thấy rằng khi thực thi lệnh git push, đầu ra hiện chứa các dòng bắt đầu bằng remote:
- đây là đầu ra của tập lệnh sau nhận đã được thực thi trên máy chủ.
Nói về những thay đổi cơ bản, các tập tin có thể được thêm, sửa đổi và xóa. Bạn có thể thực hiện các cách tiếp cận khác nhau về cách áp dụng những thay đổi này vào cơ sở dữ liệu:
Giả sử bạn đã chọn tùy chọn thứ hai, vì vậy bạn cần thực thi các tệp đã được thêm hoặc thay đổi. Chúng tôi có thể lọc các tệp như được mô tả ở đây bằng cách thêm tham số --diff-filter=AM
:
#!/bin/sh while read oval nval ref do echo List of files added or changed in the commit: git diff --name-only --diff-filter=AM $oval $nval done
Thêm một vài tệp và cũng thay đổi lại readme.md:
echo "SELECT 1;" > test1.sql echo "SELECT 2;" > test2.sql echo "SELECT 3;" > test3.sql echo "New line 2" >> readme.md git add . git commit -m "New files" git push
Đầu ra của tập lệnh hook chứa 4 tệp:
Chúng tôi chỉnh sửa các tệp test1.sql và readme.md, xóa test2.sql và thêm một tệp khác:
echo "SELECT 11;" > test1.sql echo "New line 2" >> readme.md rm test2.sql echo "SELECT 4;" > test4.sql git add . git commit -m "Modify, remove and add" git push
Chỉ các tập tin được sửa đổi và bổ sung mới được hiển thị:
Mục tiêu của chúng tôi là thực thi các tập lệnh SQL sau mỗi lần đẩy thành công, vì vậy chúng tôi cần lọc các tệp chỉ thuộc loại này; trong trường hợp của chúng tôi, chúng tôi sẽ đặt ra yêu cầu rằng tất cả chúng đều phải có phần mở rộng “.sql”. Để lọc, hãy thêm tham số -- "*.sql"
vào lệnh git diff
:
#!/bin/sh while read oval nval ref do echo List of files added or changed in the commit: git diff --name-only --diff-filter=AM $oval $nval -- "*.sql" done
Để thực thi các tập lệnh, chúng ta cũng phải có khả năng kết nối với cơ sở dữ liệu. Đối với điều này, chúng tôi sẽ tạo thông tin xác thực và kiểm tra kết nối:
mysql_config_editor set --login-path=testdb_remote --host=localhost --port=3306 --user=user_remote --password mysql --login-path=testdb_remote --database=testdb_remote
Sửa đổi tập lệnh của chúng tôi để lặp qua các tệp “.sql”, thực thi từng tệp và kiểm tra kết quả. Chúng ta cũng cần sắp xếp đầu ra danh sách để thực thi các tệp theo thứ tự yêu cầu. Với lệnh git show, chúng tôi hiển thị nội dung của tập lệnh SQL và chuyển nó qua đường ống để MySQL thực thi .
Biến “$?” sẽ chứa 0 nếu tập lệnh SQL được thực thi thành công và một giá trị khác nếu có lỗi:
#!/bin/sh while read oval nval ref do echo List of files added or changed in the commit: for file in $(git diff --name-only --diff-filter=AM $oval $nval -- "*.sql" | sort); do git show master:${file} | mysql --login-path=testdb_remote --database=testdb_remote echo "FILE: ${file} - result $?" done done
Thực hiện thêm một thử nghiệm nữa - xóa tất cả các tệp “.sql” đã tạo trước đó và tạo tập lệnh cho:
Chúng ta cũng cần thêm tiền tố (1_, 2_, v.v.) vào mỗi tên tệp để đảm bảo thứ tự thực thi mong muốn của các tệp:
rm *.sql echo "DB Initialization" >> readme.md echo " DROP TABLE IF EXISTS customers; CREATE TABLE customers ( id int UNSIGNED NOT NULL AUTO_INCREMENT, name varchar(255) DEFAULT NULL, PRIMARY KEY (id) ); " > 1_customers.sql echo " INSERT INTO customers (id, name) VALUES (1, 'John Doe'), (2, 'Jane Smith') AS new ON DUPLICATE KEY UPDATE customers.name = new.name; " > 2_customers_init.sql echo " DROP PROCEDURE IF EXISTS get_customer; DELIMITER $$ CREATE PROCEDURE get_customer(IN customer_id int UNSIGNED) BEGIN SELECT c.id, c.name FROM customers c WHERE c.id = customer_id; END $$ " > 3_get_customer.sql echo "SELECT FROM customers;" > 4_error_select.sql ls -1
Vì vậy, chúng ta có bốn tệp “.sql” cần được thực thi:
Chúng tôi thực hiện các thay đổi đối với kho lưu trữ:
Và chúng ta thấy rằng khi git push
được thực hiện, các tệp được thực thi tuần tự và kết quả thực thi (mã thoát lệnh MySQL) của mỗi tệp được hiển thị. Tệp “4_error_select.sql” chứa lỗi cú pháp nên kết quả thực thi của nó là 1.
Và cuối cùng, hãy kiểm tra những gì chúng ta có trong cơ sở dữ liệu:
mysql --login-path=testdb_remote --database=testdb_remote show tables; call get_customer(1); call get_customer(2);
Như bạn có thể thấy, bảng và thủ tục đã được tạo trong cơ sở dữ liệu từ xa. Thủ tục thực hiện thành công và trả về dữ liệu.
Để cải thiện khả năng đọc của đầu ra tập lệnh hook, bạn có thể chặn đầu ra MySQL CLI hoặc chuyển hướng nó đến một tệp nhật ký. Bạn cũng có thể phân tích kết quả thực thi lệnh MySQL và thêm logic vào tập lệnh hook.
Ví dụ: bạn có thể thực thi các tập lệnh SQL trên cơ sở dữ liệu thử nghiệm và sau đó chạy một số thử nghiệm trên cơ sở dữ liệu đó (như tôi đã mô tả ở đây ). Nếu các thử nghiệm được hoàn thành thành công trên cơ sở dữ liệu thử nghiệm, hãy chạy các tập lệnh SQL trên cơ sở dữ liệu sản xuất và có thể chạy một số thử nghiệm trên cơ sở dữ liệu đó.
Bằng cách phân tích kết quả của từng bước, bạn có thể tạo quy trình có bất kỳ cấu hình nào.
Tất nhiên, mỗi phương pháp đều có một số ưu điểm và hạn chế. Với cách tiếp cận thứ hai, cần phải đảm bảo thứ tự thực thi các tập lệnh vì chẳng hạn, chúng ta không thể chèn dữ liệu vào bảng cho đến khi nó được tạo. Cũng cần phải đảm bảo rằng bạn có thể thực thi lại các tập lệnh, tức là xử lý chính xác các tình huống khi đối tượng được tạo đã có trong cơ sở dữ liệu hoặc cơ sở dữ liệu đã chứa dữ liệu cần thêm.
Khi sử dụng hệ thống tạo phiên bản, quá trình phát triển trở nên phức tạp hơn một chút vì cần phải chính thức hóa thêm các thay đổi trong tập lệnh có định dạng được xác định trước. Tuy nhiên, bạn có thể đạt được sự linh hoạt nhất định bằng cách sử dụng tệp cài đặt.
Ưu điểm chính của kỹ thuật được mô tả là việc triển khai lập phiên bản trong cơ sở dữ liệu với rất ít nỗ lực cũng như khả năng triển khai các quy trình CI/CD .
Để đánh giá liệu điều này có hữu ích cho bạn hay không, bạn có thể bắt đầu bằng cách tự hỏi: Bạn có thường xuyên viết mã trực tiếp trong quá trình sản xuất không?