Trong bài viết này, chúng ta sẽ cùng thảo luận về một chủ đề mới có tên lâ Relational Database
. Từ relational
- tạm dịch là sự liên hệ, liên quan - được sử dụng ở đây để biểu thị cho tính chất đặc trưng của các bản ghi trong database
. Khi chúng ta muốn thiết kế một database
mà dữ liệu được lưu trữ ở dạng các bản ghi có các mối liên hệ qua lại, bổ trợ lẫn nhau; thì chúng ta có thể gọi đây là một relational database
.
Các mối liên hệ của các bản ghi được biểu thị như thế nào?
Xuất phát điểm là từ nhu cầu muốn mở rộng tính năng cho trang blog đơn giản mà chúng ta đang xây dựng. Trong bài viết trước, chúng ta đã nói tới việc giả định là giao diện web mà chúng ta xây dựng sẽ có thêm các trang đơn trình bày nội dung giới thiệu về một danh mục category
. Và lúc này hiển nhiên nội dung của mỗi trang đơn này cũng là một bản ghi và cần được lưu trữ trong database
giống như các bản ghi article
và các bản ghi admin
.
Lúc này chúng ta đang có các bản ghi article
và các bản ghi category
cùng biểu thị một phần thông tin chung - đó là tên hiển thị của các danh mục.
+----------------------------------------------------+ | article | | id: 0000 | | title: Làm Thế Nào Để Tạo Ra Một Trang Web? | | short-title: Getting Started | | | | category: html | | | | keywords: tutorial, html, document | | edited: Fri, 15 Apr 2022 11:01:34 GMT | | content: Một nội dung rất rất dài... | +----------------------------------------------------+ +----------------------------------------------------+ | article | | id: 0001 | | title: Cách Chèn Ảnh & Các Liên Kết | | short-title: Getting Started | | | | category: html | | | | keywords: tutorial, html, image, link | | edited: Fri, 15 Apr 2022 12:03:45 GMT | | content: Một nội dung khác cũng rất rất dài | +----------------------------------------------------+ +-------------------+ | category | | id: 00 | | name: html | | ... | +-------------------+
Đây là dạng biểu thị khi chúng ta đã truy xuất bằng code và chuyển các bản ghi thành các object
dữ liệu. Ở đây chúng ta đang có các bản ghi article
thuộc danh mục html
và có thuộc tính category: html
; Và một bản ghi category
biểu thị tên của danh mục với thuộc tính name: html
.
Câu chuyện lúc này là giả sử chúng ta đang có 1001 bài viết article
thuộc danh mục này và muốn thay đổi tên hiển thị của danh mục thành html5
. Hiển nhiên là trước hết chúng ta sẽ thay đổi giá trị của thuộc tính name
trong bản ghi category
ở trên. Tuy nhiên để đảm bảo kết quả hiển thị đồng nhất ở cả những trang đơn của bài viết nữa thì chúng ta sẽ cần phải sửa lại luôn cả giá trị của thuộc tính category
trong 1001 bản ghi article
.
Phương án xử lý như thế này là hoàn toàn khả thi và không khó khăn đối với khả năng xử lý của máy tính và khả năng viết code của chúng ta ở thời điểm hiện tại. Tuy nhiên ở đây chúng ta lại có thể tiếp tục cải thiện cái convention
lưu trữ dữ liệu thêm một chút - để code của chúng ta không cần phải thực hiện thao tác xử lý lặp với một tập kết quả truy vấn. Cụ thể là ở các bản ghi article
, thay vì lưu trữ trực tiếp tên hiển thị của một category
, chúng ta có thể lưu trữ trị số định danh id
của category
đó.
+-------------------------+ | article | | id: 0000 | | title: ... | | short-title: ... | | category-id: 00 | | ... | +-------------------------+ +-------------------------+ | article | | id: 0001 | | title: ... | | short-title: ... | | category-id: 00 | | ... | +-------------------------+ +-------------------+ | category | | id: 00 | | name: html | | ... | +-------------------+
Lúc này, khi truy vấn nội dung của một bản ghi article
và gửi phản hồi cho trình duyệt web, chúng ta có thể thực hiện thao tác tìm kiếm tên hiển thị của danh mục tương ứng bằng cách đi từ trị số được lưu ở khóa category-id
của article
tìm tới bản ghi category
tương ứng và truy xuất giá trị của thuộc tính name
.
Và như vậy là các bản ghi article
đã có sự lệ thuộc vào thông tin chi tiết được cung cấp bởi các bản ghi category
và chúng ta đã có thể gọi cơ sở dữ liệu của chúng ta là relational database
.
Các dạng thức liên hệ có thể xuất hiện trong relational database
Trong ví dụ ở phần trên, chúng ta có dữ liệu của một bản ghi category
được sử dụng bởi 1001 bản ghi article
thuộc danh mục html
. Dạng thức liên hệ này được quy ước với tên gọi là one-to-many
- hay một-và-1001
- đại ý nói là khi một bản ghi thuộc một kiểu dữ liệu này được tham chiếu tới từ 1001 bản ghi thuộc một kiểu dữ liệu khác.
Bên cạnh đó thì trong những trường hợp sử dụng khác, chúng ta sẽ có thể có những dạng thức liên hệ khác là -
- Dạng thức
one-to-one
- haymột-và-một
- khi một bản ghi thuộc kiểu dữ liệu này được tham chiếu tới từ duy nhất một bản ghi thuộc kiểu dữ liệu khác, và ngược lại. - Dạng thức
many-to-many
- hay1001-và-1001
- khi mỗi bản ghi thuộc kiểu dữ liệu này có thể được tham chiếu tới từ 1001 bản ghi thuộc kiểu dữ liệu khác, và ngược lại.
a. one-to-one
Dạng thức one-to-one
thường được sử dụng khi chúng ta muốn tách rời một nhóm dữ liệu khỏi một bản ghi lớn, để sử dụng cho mục đích truy xuất riêng và biểu thị tới người dùng hoặc xử lý logic đặc trưng nào đó của web hay phần mềm.
Ví dụ như khi bạn xây dựng một nền tảng blog cho nhiều người dùng; việc quản lý thông tin người dùng có thể được lưu trữ bằng các bản ghi user
và person
như sau -
+-----------------------+ +-----------------------+ | user | | person | | id: ... | | id: ... | | username: ... | | firstname: ... | | password: ... | | lastname: ... | | | | address: ... | | person-id: ... | | mobile: ... | +-----------------------+ | email: ... | | ... | +-----------------------+
Ở đây thông tin của mỗi người dùng được biểu thị bằng một bản ghi lớn và được tách ra làm hai nhóm thông tin user
và person
. Mục đích của thiết kế này là để tách rời nhóm thông tin hiển thị person
khỏi các thông tin dành cho chức năng đăng nhập. Điều này giúp cho chúng ta có thể sử dụng các bản ghi person
trong code xử lý các tác vụ khác mà không gặp phải rủi ro về việc thao tác nhầm trên các thông tin đăng nhập cần bảo vệ.
b. one-to-1001
Với ví dụ mở đầu của bài viết thì chúng ta đã biết về one-to-1001
rồi. Dạng thức này được sử dụng khi phần mềm của chúng ta cần phân chia các bản ghi của một kiểu dữ liệu nào đó thành các hạng mục không giao thoa - tức là mỗi bản ghi sẽ chỉ thuộc một hạng mục duy nhất.
c. 1001-to-1001
Để lấy ví dụ mô tả cho dạng thức này, chúng ta hãy giả định là blog đơn giản mà chúng ta đang xây dựng sẽ có thêm một tính năng nữa - đó là các trang đơn biểu thị cho các từ khóa keywords
hay còn được gọi là các thẻ tags
. Đại loại là các trang đơn đó sẽ có dạng giống với một trang hiển thị cho thẻ java
của Viblo đi cho dễ hiểu.
https://viblo.asia/tags/tutorial
Trang đơn này hiển thị các bài viết được các tác giả gắn thẻ tutorial
và không quan trọng là các bài viết này thuộc danh mục gì - ngôn ngữ nào, framework nào, v.v... - cứ miễn được gắn thẻ tutorial
là sẽ được hiển thị.
Như vậy là lúc này chúng ta sẽ có thêm các bản ghi tag
thay thế cho việc lưu trữ các từ khóa trực tiếp trong các bản ghi article
. Đồng thời, chúng ta có thể thấy rằng mỗi bản ghi tag
có thể được sử dụng bởi nhiều bản ghi article
, và ngược lại.
Việc thể hiện mối liên hệ giữa các bản ghi article
và các bản ghi tag
trong database
ở trường hợp này sẽ tùy thuộc vào các khả năng mà môi trường phần mềm cung cấp. Do chúng ta đang lưu trữ bằng các tệp tĩnh tự tạo quy ước và xử lý bằng code JavaScript, các liên kết giữa các bản ghi có thể biểu thị bằng cách lưu một mảng id
của các tag
trong mỗi bản ghi article
- và ngược lại.
+----------------------------------------+ | article | | id: ... | | ... | | tag-id: 00000000, 00000001, ... | | ... | +----------------------------------------+ +------------------------------------+ | tag | | id: ... | | name: ... | | article-id: 0001, 0009, ... | | ... | +------------------------------------+
Như vậy là chúng ta đã có thể truy xuất tới tên của các tag
liên quan từ mỗi bản ghi article
- và ngược lại.
Phần mềm quản trị database
Như vậy là tính tới thời điểm này, chúng ta đã đi qua những kiến thức cơ bản về database
và đã có thể bắt tay vào việc viết code chi tiết cho một module
quản lý database
- chính là tệp manager.js
mà chúng ta đã có từ quy ước ở đầu Sub-Series
này. Đó có thể được xem là một phần mềm quản trị database
được nhúng trong bộ code web mà chúng ta đang xây dựng.
Việc tự thiết kế và viết một phần mềm quản trị database
cho nhu cầu sử dụng không quá phức tạp là rất quan trọng. Tuy nhiên mọi thứ sẽ trở nên dễ dàng hơn nếu như chúng ta có một nguồn tham khảo. Và cách tốt nhất để có kinh nghiệm về việc thiết kế một thứ gì đó - là chúng ta cần sử dụng một thứ đã được xây dựng sẵn bởi những người đi trước và đã được tin tưởng, sử dụng bởi cộng đồng.
Nói riêng về relational database
, nếu như bạn Google thử từ khóa này thì sẽ thấy các kết quả tìm kiếm đều liên quan tới một hệ quản trị database
có tên là SQL ... gì đó
. Hệ quản trị này bao gồm một database
trừu tượng được lưu trữ ở dạng các tệp đặc biệt mà chúng ta sẽ không bao giờ phải mở xem trực tiếp; và một phần mềm quản trị cho phép chúng ta tự thiết kế dạng thức của các kiểu dữ liệu ở dạng các bảng chứa các bản ghi.
Môi trường vận hành của SQL ...
có phần kém linh động hơn so với khả năng truy xuất các tệp tĩnh của JavaScript mà chúng ta đang sử dụng. Và đối với dạng thức liên hệ many-to-many
ở trên thì chúng ta sẽ cần thiết kế một bảng dữ liệu trung gian để biểu thị mối liên hệ giữa các bản ghi article
và các bản ghi tag
.
Tuy nhiên bù lại thì chúng ta sẽ có được sự đảm bảo về mặt nhất quán dữ liệu nhờ các công cụ hỗ trợ tạo các ràng buộc giữa các bản ghi. Và từ đó chúng ta cũng sẽ tự tin hơn trong việc thiết kế và viết phần mềm quản trị database
đơn giản cho nhu cầu sử dụng hiện tại. Và vì vậy nên...
(Chưa đăng tải) [SQL] Bài 1 - SQL Là Cái Gì?
Lại thêm Sub-Series mới à? Chúng ta vẫn còn NodeJS, ExpressJS, và Database ở đây vẫn còn chưa đâu vào đâu...
Mình biết, mình biết... thế nhưng mục tiêu gần nhất của chúng ta là có được một blog cá nhân để sử dụng chứ không phải là hoàn thiện một Sub-Series
kiến thức nào cả. Nếu như bạn chọn dừng lại ở thiết kế web đơn giản chỉ cần 1001 trang đơn hiển thị các bài viết và một trang chủ thì chúng ta có thể dừng lại ở đây được rồi. Tuy nhiên nếu như bạn dự định rằng blog của bạn sẽ có luôn những tính năng khác như các trang đơn thể hiện cho mỗi danh mục và mỗi tag
thì chúng ta nên đi tiếp.
Hmm.. nhưng mà nếu tính từ thời điểm chúng ta bắt đầu học code server-side
cho tới giờ thì hình như chặng đường mà chúng ta đã đi qua cũng khá dài rồi; Và có lẽ chúng ta cần có một kết quả biểu thị để có tinh thần tiếp tục tìm hiểu kiến thức mới. Mặc dù là rủi ro rằng sau một thời gian nữa chúng ta có thể sẽ phải thực hiện khá nhiều thay đổi đối với cả database
và code xử lý khi có thêm những kiến thức và tầm nhìn mới.
Hmm.. nếu vậy chúng ta có thể quyết định thế này đi.. Bây giờ chúng ta sẽ xì-tốp cái Sub-Series SQL
tạm một quãng thời gian để tập trung viết code chi tiết quản lý database
đơn giản và hoàn thiện trang blog cá nhân với một trang chủ và 1001 bài viết đã. À còn cả trang đăng nhập quản trị và giao diện soạn thảo bài viết đơn giản nữa.
Sau khi đăng tải xong trang blog cá nhân đơn giản trên Glitch.com
, chúng ta sẽ quay lại thực hiện Sub-Series SQL
để học thêm kiến thức mới và tính đến chuyện mở rộng tính năng của trang blog sau đó. Còn ở thời điểm mở rộng thêm tính năng cho blog, nhỡ như chúng ta có phải bỏ nguyên cái project
đang có để xây dựng lại từ đầu thì.. đành chịu thôi. Bởi vì ở thời điểm hiện tại, chúng ta không thể cứ cố gắng tưởng tượng về 1001 bước đi tiếp theo trong hành trình Tự Học Lập Trình Web Một Cách Thật Tự Nhiên của chúng ta được.
Vậy chúng ta cứ quyết định vậy nhé. Hẹn gặp lại bạn trong các bài viết tiếp theo.
(Sắp đăng tải) [Database] Bài 4 - Viết Code Quản Lý Database Đơn Giản