Sử dụng Flyway để thực hiện migration trong PHP

Migration là gì

Migration là một tính năng rất hữu dụng khi chúng ta thay đổi database (thường là MySQL) và muốn quản lý version của những lần thay đổi đó. Thay đổi có thể là thêm bảng, thêm cột vào bảng hay thay đổi các cột trong cùng một bảng.

Có thể việc bạn phát triển dự án solo thì không cần quan tâm tracking mã nguồn của SQL nhưng khi làm việc nhóm thì dều đó là không thể chấp nhận được, nếu bạn đã dùng các framework lớn của PHP thì migration sẽ được tích hợp như là built-in, có thể kể ra doctrin của Symfony, bundle của CakePHP hay devtools của Phalcon.

Ngoài ra PHP còn có một thư viện Phinx cũng khá là hay nhưng tất cả các thư viện trên đều có một nhược điểm đó là bạn phải viết code định nghĩa hay thêm các tuỳ chọn vào các class mà bạn đã tạo ở trên, cá nhân tôi không thích lắm tôi chỉ thích sau khi sữa một trường dữ liệu hoặc thêm vào dữ liệu thì chỉ dùng câu SQL thông thường thôi:

Bài toán

Giả sử ban đầu tôi có phiên bản dầu tiên của SQL dự án là V1.0.0__BaseVersion.sql với nội dung như bên dưới:

[sql]

DROP TABLE IF EXISTS `gsviec_acl_access_list`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `gsviec_acl_access_list` (
`arl_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`arl_tnt_id` int(11) unsigned NOT NULL,
`arl_grp_id` int(11) unsigned NOT NULL,
`arl_roles_name` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`arl_resources_name` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`arl_access_name` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
`arl_allowed` int(3) unsigned NOT NULL,
`arl_created_id` int(11) unsigned NOT NULL DEFAULT ‘0’,
`arl_created_date` int(11) unsigned NOT NULL DEFAULT ‘0’,
`arl_updated_id` int(11) unsigned DEFAULT ‘0’,
`arl_updated_date` int(11) unsigned DEFAULT ‘0’,
`arl_delete_flag` tinyint(1) unsigned NOT NULL DEFAULT ‘0’,
PRIMARY KEY (`arl_id`),
UNIQUE KEY `unique_key` (`arl_tnt_id`,`arl_roles_name`,`arl_resources_name`,`arl_access_name`),
KEY `arl_tnt_id` (`arl_tnt_id`),
KEY `arl_grp_id` (`arl_grp_id`),
KEY `arl_access_name` (`arl_access_name`),
KEY `arl_created_id` (`arl_created_id`),
KEY `arl_created_date` (`arl_created_date`),
KEY `arl_updated_id` (`arl_updated_id`),
KEY `arl_updated_date` (`arl_updated_date`),
KEY `arl_delete_flag` (`arl_delete_flag`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT=’Stores access lists’;
/*!40101 SET character_set_client = @saved_cs_client */;


— Table structure for table `gsviec_status`

DROP TABLE IF EXISTS `gsviec_status`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `gsviec_status` (
`sta_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`sta_tnt_id` int(11) unsigned NOT NULL,
`sta_name` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`sta_type` tinyint(1) unsigned NOT NULL,
`sta_color_background` varchar(256) COLLATE utf8_unicode_ci NOT NULL,
`sta_color_text` varchar(256) COLLATE utf8_unicode_ci NOT NULL,
`sta_order` int(11) unsigned NOT NULL,
`sta_description` varchar(1024) COLLATE utf8_unicode_ci NOT NULL,
`sta_created_id` int(11) unsigned NOT NULL DEFAULT ‘0’,
`sta_created_date` int(11) unsigned NOT NULL DEFAULT ‘0’,
`sta_updated_id` int(11) unsigned DEFAULT ‘0’,
`sta_updated_date` int(11) unsigned DEFAULT ‘0’,
`sta_delete_flag` tinyint(1) unsigned NOT NULL DEFAULT ‘0’,
PRIMARY KEY (`sta_id`,`sta_tnt_id`),
KEY `sta_tnt_id` (`sta_tnt_id`),
KEY `sta_name` (`sta_name`),
KEY `sta_type` (`sta_type`),
KEY `sta_created_id` (`sta_created_id`),
KEY `sta_created_date` (`sta_created_date`),
KEY `sta_updated_id` (`sta_updated_id`),
KEY `sta_updated_date` (`sta_updated_date`),
KEY `sta_delete_flag` (`sta_delete_flag`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT=’Stores statuss’;
/*!40101 SET character_set_client = @saved_cs_client */;

[/sql]

Sau một vài ngày phát triển dự án chúng tôi cần phải thêm vào một trường dữ liệu vào table gsviec_status chúng tôi sẽ định nghĩa nó trong tập tin V1.0.10__AddNotificationToStatusTable.sql

[sql]

ALTER TABLE co_status ADD sta_notification TINYINT(1) NOT NULL default 1 after sta_description;
ALTER TABLE co_status ADD INDEX `sta_notification` (`sta_notification` ASC);

[/sql]

Với cách làm như thế thì bạn thấy khá là đơn giản chỉ cần export câu SQL mà bạn đã thực thi là xong không cần quan tâm code gì cả:

Giải quyết

Như tôi nói ở trên hiện tại các FW PHP chỉ hệ trợ Migrate thông qua viết code do đó chúng tôi sẽ hướng dẫn bạn cách dùng flywaydb để giải quyết vấn dề này

Flywaydb

Trước tiên Flywaydb nó viết bằng Java do đó nó có thể chạy bất cứ trên HĐH nào, và tất nhiên công dụng của nó là Migration Database

Dưới đây là những lợi ích

Nó hỗ trợ nhiều hệ cơ sở dữ liệu như Oracle, SQL Server, SQL Azure, DB2, DB2 z/OS, MySQL (including Amazon RDS), MariaDB, Google Cloud SQL, PostgreSQL (including Amazon RDS and Heroku), Redshift, Vertica, H2, Hsql, Derby, SQLite, SAP HANA, solidDB, Sybase ASE, Phoenix and EnterpriseDB.

Mã nguồn mỡ miễn phí, rất thích hợp cho việc tích hợp CI/CD. DBA chỉ việc xuất ra SQL không cần quan tâm tới code của ứng dụng đó.

Không quan tâm bất cứ ngôn ngữ nào mà bạn sử dụng dù cho bạn dùng PHP, Ruby, Node, Java tất cả đều OK cả.

Hỗ trợ sữa các table nếu bị lỗi, validate, clean, xem thông tin cơ sở dữ liệu

Cài đặt

Để cài đặt nó bạn chỉ việc cài đặt Java sau đó vào trang chủ nó tải về thôi, còn trong hướng dẫn này tôi sẽ dùng docker cho demo, hiện tại đã có một tác giả tạo sẵn docker-flyway bạn có thể vào đây để tham khảo Dockerized flywa

[code lang=text]
docker pull dhoer/flyway

[/code]

Chú ý nếu bạn nào chưa biết Docker là gì có thể muốn xem qua khóa học Khóa Học Docker căn bản

Cách dùng

Trước tiên bạn cần phải định nghĩa cái tập tin SQL theo quy tắc thứ tự của bản chữ cái và số, ví dụ bạn định nghĩa 2 tập tin 1.sql, 2.sql thì nó sẽ thực hiện 1.sql trước sau đó đến 2.sql nhưng thực tế bạn nên định nghĩa tập tin theo cú pháp V__ như trong ví dụ bên trên chúng tôi định nghĩa V1.0.0__BaseVersion.sql, V1.0.10__AddNotificationToStatusTable.sql, còn đây là dự án thực tế của chúng tôi:

Screenshot at Apr 26 21 59 06 1

Cú pháp dùng khá đơn giản bạn chỉ cần chạy lệnh sau:

[code lang=text]
flyway migrate -url=… -user=… -password=…

[/code]

Hoặc lệnh bên dưới

[code lang=text]
flyway -url=jdbc:localhost://mydb -schemas=myschema -user=root -password=P@ssw0rd migrate

[/code]

Tất nhiên nếu bạn đã định nghĩa các tham số như username, password trong tập tin /conf/flyway.conf của flyway thì cú pháp nó chỉ còn như thế này:

[code lang=text]
flyway migrate

[/code]

dưới đây là tập tin cấu hình /conf/flyway.conf, để hiểu rõ nó hơn thì bạn nên vào trang chủ nó coi:)

[code lang=text]
flyway.url=jdbc:h2:file:./foobardb
flyway.user=SA
flyway.password=

[/code]

Nếu dùng Docker thì bạn chỉ việc dùng lệnh như thế này thôi:

[code lang=text]
docker run –rm -v $(pwd):/flyway/sql dhoer/flywayjdbc:mysql://mysql -schemas=gsviec -user=root -password=secret migrate

[/code]

Dưới đây là demo dự án thực tế của tôi

[php]
version: ‘2’

services:
mysql:
image: mysql
restart: always
env_file:
– ./docker/variables.env
# volumes:
# – ./docker/data/mysql:/var/lib/mysql
flyway:
image: dhoer/flyway
restart: ‘no’
working_dir: /flyway/sql
volumes:
– ./migrations/sql:/flyway/sql
command: -url=jdbc:mysql://mysql -schemas=${MYSQL_DATABASE} -user=root -password=${MYSQL_ROOT_PASSWORD} migrate

depends_on:
– mysql

[/php]

sau khi tôi định nghĩa xong tập tin docker-compose.yml tôi chạy lệnh docker-compose config để kiểm tra, nếu bạn thấy như thế này thì OK

Screenshot at Apr 26 22 13 10 1

Công việc còn lại chỉ còn là chạy lệnh

[code lang=text]
docker-compose up -d

[/code]

sau đó chờ vài giây để nó khởi tạo xong mysql rồi chạy lệnh

[code lang=text]
docker-compose up flyway

[/code]

trong thực tế tôi thường viết bash shell như sau để tiết kiệm thời gian gõ lệnh

[bash]
#!/bin/bash
#Do something before run docker

docker-compose config
docker-compose up -d

echo ‘Wating a monment to flyway migrate your database!’
sleep 20

docker-compose up flyway

[/bash]

Thì bạn sẽ có kết quả như hình bên dưới:

nVu5QYC

Kết luận

Migration thực sự là một kĩ thuật khá là quan trọng nếu như dự án bạn thây đổi database liên tục. Với flyway công việc thật sự không thể dễ dàng hơn. Nếu bạn còn chưa ứng dụng vào dự án của mình thì mình khuyên là rất nên thử, sẽ đến lúc bạn muốn cảm ơn flyway migration rất nhiều.

Như mọi khi nếu thấy bài viết hay hãy chia sẽ và like!!!

Leave a Comment

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Scroll to Top