So sánh 4 thư viện DB backend cho Rust
(aarambhdevhub.medium.com)Nếu bạn từng thực sự xây dựng backend bằng Rust, hẳn đã có lúc đâm đầu vào bức tường này. Đến lúc cần cơ sở dữ liệu, bốn thư viện với triết lý, đánh đổi riêng và cả một đội quân người hâm mộ trên Reddit sẽ đồng loạt nhìn chằm chằm vào bạn.
Tôi cũng vậy. Trong 1 năm qua, tôi đã triển khai production thực tế với Diesel, SQLx, SeaORM và Rusqlite. Có lựa chọn hóa ra rất hợp, cũng có thứ mà nếu làm lại tôi sẽ chọn khác. Một vài điều thật sự khá bất ngờ.
Không có diễn ngôn marketing, cũng không có kiểu lấp lửng như “còn tùy tình huống”. Đây là nhận xét thẳng thắn từ một người đã dùng cả bốn trong code vận hành thực tế.
Năm 2026, vì sao lại làm việc với DB bằng Rust?
Trước hết, hãy nói rõ chuyện này. Vì sao không dùng SQLAlchemy với Python hay Prisma với Node?
Có ba lý do khiến người ta chọn Rust cho ứng dụng xoay quanh DB.
Độ an toàn ở thời điểm biên dịch ở đây đúng là ở một đẳng cấp khác. Một số thư viện trong nhóm này thực sự đối chiếu câu lệnh SQL với schema DB và xác thực ngay lúc compile. Gõ sai tên cột? Trình biên dịch bắt được. Kiểu dữ liệu không khớp trong mệnh đề WHERE? Bị chặn trước khi code chạy. Có nhấn mạnh bao nhiêu việc này giúp giảm debug lúc 3 giờ sáng cũng vẫn chưa đủ.
Bất đồng bộ cuối cùng cũng đã trưởng thành. Vài năm trước, truy cập DB bất đồng bộ trong Rust còn rất gồ ghề. Bạn phải vật lộn với borrow checker, tung hứng lifetime và đối phó với những thư viện chưa thật sự chín. Còn ở năm 2026? Nó đơn giản là chạy được. Tokio đã rất vững, còn các thư viện cũng đã tìm ra hướng đi.
Bạn gần như không cần lo về hiệu năng. Overhead của ORM không gặm mất ngân sách xử lý mỗi request. Garbage collector không đứng hình giữa giao dịch. Query được chạy, kết quả được trả về, và bộ nhớ được giải phóng một cách xác định. Nó vận hành tốt đến mức gần như nhàm chán.
Bốn ứng viên
Hãy cùng xem các phiên bản mới nhất tính đến tháng 2 năm 2026.
- Diesel (v2.3.6, tháng 1 năm 2026) — ORM đầy đủ với SQL ở thời điểm biên dịch
- SQLx (v0.8.6, bản stable hiện tại) — bộ công cụ SQL bất đồng bộ (không phải ORM)
- SeaORM (v2.0, tháng 1 năm 2026) — ORM động, ưu tiên bất đồng bộ
- Rusqlite (v0.38.0, tháng 12 năm 2025) — wrapper SQLite gọn nhẹ
Đây là những công cụ về cơ bản giải quyết các bài toán liên quan nhưng theo những cách rất khác nhau. Tôi sẽ đi từng cái một.
Diesel: kẻ bắt bug trước cả bạn
Phù hợp nhất khi: bạn muốn tối đa hóa độ an toàn ở thời điểm biên dịch và team có schema tương đối ổn định
Diesel đã tồn tại từ năm 2015. Trong thế giới Rust, như vậy gần như là cổ đại. Và độ chín của nó thể hiện ra theo nghĩa tích cực nhất.
Cốt lõi là thế này. Nếu code Diesel biên dịch được thì SQL là hợp lệ. Đây không phải khẩu hiệu marketing, mà đúng là nó hoạt động như vậy. Diesel sinh ra các kiểu Rust từ schema DB, rồi trình biên dịch sẽ đối chiếu mọi query bạn viết với các kiểu đó để xác thực.
Vì sao Diesel vẫn luôn hấp dẫn tôi
Xác thực ở thời điểm biên dịch rất dễ gây nghiện. Chỉ cần một lần trải nghiệm cảnh “trình biên dịch bắt được một JOIN sai trước cả khi chạy test”, bạn sẽ thấy quay về SQL dạng chuỗi là một việc khá liều lĩnh. Tháng trước tôi refactor schema — đổi tên ba cột và thay đổi kiểu dữ liệu — Diesel đã chỉ ra mọi query cần sửa ngay tại lúc compile. Không sót. Một. Cái. Nào.
Abstraction zero-cost ở đây không chỉ là khẩu hiệu. SQL mà Diesel sinh ra về bản chất giống hệt SQL bạn tự viết tay. Tôi đã so execution plan và chúng giống nhau. Bạn có được độ an toàn của ORM lẫn hiệu năng của raw SQL cùng lúc.
Migration hoạt động đúng nghĩa. Nghe có vẻ là tiêu chuẩn thấp, nhưng sau khi từng vật lộn với công cụ migration ở các hệ sinh thái khác, hệ thống migration của Diesel tạo cảm giác chắc chắn đến dễ chịu. Tạo, chạy, rollback — cứ thế mà dùng.
Điểm trừ thẳng thắn
Bất đồng bộ là thứ được gắn thêm vào chứ không phải cốt lõi sẵn có. Bản thân Diesel là đồng bộ. Nếu muốn async, bạn cần diesel-async, nó hoạt động tốt nhưng vẫn là thêm một dependency và thêm gánh nặng tinh thần. Nếu bạn đi từ async native của SQLx hay SeaORM sang, điều này khá dễ nhận ra.
Độ dốc học tập khá cao. Hệ thống kiểu của Diesel rất mạnh, mà thứ gì mạnh thì cũng phức tạp. Khi viết query sai, lỗi compile tuy đúng về mặt kỹ thuật nhưng đôi khi trông như một cơn nôn mửa generic dài 40 dòng. Bạn rồi sẽ học được cách đọc nó, nhưng tuần đầu tiên sẽ khá mệt.
Query động là một nỗi đau. Nếu cần tạo những query có cấu trúc thay đổi lúc runtime — như endpoint tìm kiếm có bộ lọc tùy chọn — Diesel sẽ chống cự. Nó muốn hình dạng query là tĩnh. Khi query mang tính động, bạn sẽ thấy mình vật lộn với hệ thống kiểu nhiều hơn cả logic nghiệp vụ.
Khi nào nên chọn Diesel
- Dự án PostgreSQL hoặc MySQL và schema không thay đổi hàng tuần
- Độ an toàn ở thời điểm biên dịch là điều tuyệt đối không thể thỏa hiệp
- Đây là code production sẽ sống nhiều năm và tính đúng đắn rất quan trọng
- Nếu không có lý do nào khác, đây là lựa chọn mặc định
SQLx: cứ viết SQL, an toàn sẽ đi kèm
Phù hợp nhất khi: bạn là lập trình viên ưu tiên SQL và muốn xác thực ở thời điểm biên dịch mà không phải học DSL
Nói thẳng ra nhé. SQLx không phải ORM. Nó không sinh query cho bạn, cũng không quản lý quan hệ. Nó là bộ công cụ SQL. Nhưng nhiều người dùng nó ở đúng vị trí mà bình thường sẽ dùng ORM, và thành thật mà nói? Với nhiều dự án, đó lại là lựa chọn tốt hơn.
Phép màu hoạt động như sau. Bạn viết raw SQL dưới dạng chuỗi. SQLx sẽ kết nối tới DB thật trong lúc compile để xác thực query đó. Thiếu bảng, sai tên cột, không khớp kiểu dữ liệu — lỗi compile. Bạn có được mức an toàn kiểu Diesel trong khi vẫn viết SQL bình thường.
Điều SQLx thực sự làm rất tốt
Nếu bạn biết SQL thì bạn biết SQLx. Không có DSL query phải học. Không có mô hình tư duy mới. Bạn chỉ dùng chính SQL mình đã biết, rắc thêm vài macro, còn lại để trình biên dịch lo. Từ kinh nghiệm đưa lập trình viên junior vào dự án SQLx, chỉ cần vài giờ. Không phải vài ngày.
Bất đồng bộ ngay từ ngày đầu. SQLx được sinh ra cho Rust async. Dùng Tokio hay async-std đều được, chỉ cần chọn runtime bạn muốn. Không có crate riêng hay lớp tương thích nào cả. Truy cập DB bất đồng bộ lẽ ra phải như thế này.
QueryBuilder xử lý query động rất tốt. Đây là chỗ SQLx âm thầm thắng Diesel. Cần một endpoint tìm kiếm cho phép người dùng lọc theo bất kỳ tổ hợp nào trong 12 trường? QueryBuilder của SQLx cho phép bạn ghép các query động như vậy một cách trực quan. Dù query được dựng từng mảnh, tham số vẫn được parameterize nên tránh được injection.
Điểm trừ thẳng thắn
DB phải chạy trong lúc biên dịch. Đây là điểm gây tranh cãi nhất của SQLx. Pipeline CI cần quyền truy cập DB, và lập trình viên mới phải khởi động DB trước khi compile. Chế độ offline có thể cache metadata của query, nhưng đó vẫn là một bước workflow bổ sung mà bạn phải nhớ.
Không có tính năng ORM cấp cao. Không có tải quan hệ. Không có eager/lazy loading. Không có JOIN tự động. Nếu bạn có mô hình dữ liệu phức tạp với quan hệ lồng nhau, bạn sẽ phải tự viết toàn bộ SQL. Với CRUD đơn giản thì ổn. Với đồ thị dữ liệu phức tạp thì sẽ nhanh chóng thành việc lặp lại nhàm chán.
Chế độ offline đòi hỏi sự kỷ luật. Nếu muốn build mà không có DB, bạn chạy cargo sqlx prepare để sinh các file .sqlx. Những file này chứa metadata query đã được cache. Nếu bạn thay query rồi quên sinh lại? Bạn sẽ có một bản build cũ. Nó vẫn hoạt động, nhưng tạo ma sát.
Khi nào nên chọn SQLx
- Team đã quen tư duy bằng SQL và không muốn thêm lớp trừu tượng
- Query động là yêu cầu cốt lõi
- Bạn đang bắt đầu dự án mới và muốn con đường ngắn nhất đến code DB chạy được
- Bạn cần truy cập DB bất đồng bộ mà không phải thỏa hiệp
SeaORM: thứ mang cảm giác quen thuộc
Phù hợp nhất khi: bạn muốn trải nghiệm ORM hiện đại với async và query động
Nếu bạn từng dùng Django ORM, ActiveRecord hay Eloquent, SeaORM sẽ tạo cảm giác quen. Và tính đến bản phát hành 2.0 vào tháng 1 năm 2026, nó thực sự đã sẵn sàng cho production.
SeaORM đi theo hướng ngược lại hoàn toàn với Diesel. Thay vì xác thực ở thời điểm biên dịch, nó hoạt động ở runtime. Bạn đánh đổi một chút an toàn để lấy sự linh hoạt mà các thư viện khác khó theo kịp.
Vì sao SeaORM 2.0 đáng chú ý
Quan hệ hoạt động đúng như bạn mong đợi. Một-nhiều, nhiều-nhiều, eager loading, lazy loading — SeaORM xử lý được tất cả. Nếu bạn có mô hình dữ liệu phức tạp kiểu user-post-comment-tag, SeaORM cho phép bạn duyệt qua các quan hệ đó rất tự nhiên. Không có cảm giác phải đánh vật với DB.
Query động là công dân hạng nhất. Bộ lọc tùy chọn? Sắp xếp có điều kiện? Phân trang? SeaORM xử lý tất cả những thứ đó gần như không cần suy nghĩ. Query builder của nó hoạt động ở runtime nên cấu trúc có thể thay đổi tự do. Đây là chỗ Diesel đau khổ và SeaORM tỏa sáng.
Các tính năng của 2.0 thực sự hữu ích. Entity Loader giải quyết bài toán N+1 một cách gọn gàng — thay vì bắn query riêng lẻ cho từng entity liên quan, nó load theo lô hiệu quả hơn. sea-orm-sync cung cấp biến thể đồng bộ cho công cụ CLI và script. Nested ActiveModel giúp các thao tác insert phức tạp trở nên sạch sẽ hơn.
Khả năng sinh entity thực sự tiết kiệm thời gian. Trỏ sea-orm-cli vào DB là nó tạo ra các Rust entity. Schema đổi à? Sinh lại là xong. Không phải việc gì hào nhoáng, nhưng tự động hóa nó sẽ giảm bug đến từ việc tự viết struct bằng tay.
Điểm trừ thẳng thắn
Lỗi runtime là có thật. Không giống Diesel hay SQLx, SeaORM không bắt schema mismatch ở thời điểm biên dịch. Bạn đổi tên cột rồi quên cập nhật entity? Lỗi runtime. Muốn bù cho điều này, bạn cần test coverage đủ tốt.
Nó vẫn còn tương đối mới. SeaORM 2.0 thì ổn định, nhưng hệ sinh thái vẫn nhỏ hơn. Ít bài blog hơn, ít câu trả lời trên Stack Overflow hơn, ít thread kiểu “tôi cũng gặp lỗi này” hơn. Bạn sẽ phụ thuộc vào tài liệu chính thức và Discord nhiều hơn.
Có một chút overhead lúc runtime. Việc dựng query động có cái giá của nó. Mức giá này nhỏ — với 99% ứng dụng thì có thể bỏ qua — nhưng nếu bạn đang vắt từng microsecond, Diesel hoặc SQLx sẽ nhanh hơn.
Khi nào nên chọn SeaORM
- Bạn đang xây dựng web API với quan hệ phức tạp giữa các entity
- Tìm kiếm/lọc động là tính năng chính
- Team đến từ Django, Rails hoặc Laravel và muốn mô hình quen thuộc
- Tốc độ phát triển quan trọng hơn bảo đảm ở thời điểm biên dịch
Rusqlite: lựa chọn hiển nhiên (cho SQLite)
Phù hợp nhất khi: công cụ CLI, ứng dụng desktop, hệ thống nhúng và mọi thứ dùng SQLite
Gọi Rusqlite là “ORM” thì hơi rộng tay. Nó là một wrapper cho SQLite. Nhưng đó cũng chính là điểm mạnh — làm một việc, và làm nó cực tốt.
Nếu dự án của bạn dùng SQLite — mà rất nhiều dự án Rust đúng là như vậy — thì Rusqlite là lựa chọn hiển nhiên, gần như không cần tranh cãi.
Vì sao Rusqlite đơn giản là chạy tốt
SQLite được bundle sẵn là một điều tuyệt vời. Bật feature flag bundled, Rusqlite sẽ biên dịch SQLite trực tiếp vào binary. Không phụ thuộc hệ thống. Không còn cảnh “hãy cài sqlite3-dev đi”. Binary sẽ chạy ở bất cứ đâu. Tôi từng phát hành công cụ CLI lên một máy trống trơn và nó cứ thế chạy.
Nó mỏng vừa đủ. Rusqlite không cố tỏ ra thông minh. Nó cho bạn connection, prepared statement, transaction, rồi đặt thêm lớp an toàn kiểu dữ liệu của Rust lên trên. Borrow checker ngăn việc dùng sai tài nguyên. Prepared statement ngăn injection. Hết. Thế là toàn bộ thư viện này.
Nó phơi bày các tính năng riêng của SQLite. Hàm SQL tự định nghĩa, virtual table, full-text search, phần mở rộng JSON — Rusqlite cho bạn chạm tới trọn bộ tính năng của SQLite. ORM tổng quát thường giấu các thứ này phía sau lớp trừu tượng. Rusqlite thì để bạn dùng trực tiếp.
Điểm trừ thẳng thắn
Chỉ dùng được với SQLite. Nếu bạn cần PostgreSQL hay MySQL thì Rusqlite không phải thư viện dành cho bạn. Hết chuyện.
Không có tiện ích kiểu ORM. Không có query builder. Không có xử lý quan hệ. Không có migration sẵn (dù bạn có thể dùng refinery hoặc rusqlite_migration). Bạn phải tự viết chuỗi SQL và tự map kết quả bằng tay.
Chỉ có đồng bộ. Rusqlite không làm async. Với công cụ CLI hay ứng dụng desktop thì thường không thành vấn đề. Nếu là web server, bạn sẽ phải dùng hỗ trợ SQLite của SQLx hoặc bọc nó bằng thread pool.
Khi nào nên chọn Rusqlite
- Bạn đang làm công cụ CLI cần lưu trữ cục bộ
- Đây là ứng dụng desktop với DB nhúng
- Mọi dự án mà SQLite là lựa chọn DB phù hợp
- Bạn triển khai vào môi trường không thể cài DB server
Tôi thực sự ra quyết định như thế nào
Sau khi đã dùng cả bốn trong production, đây là framework trong đầu tôi.
Có phải SQLite không? → Rusqlite. Hết. Đừng nghĩ nhiều.
Bạn muốn xác thực SQL ở thời điểm biên dịch + DSL query? → Diesel. Đây là canh cược an toàn nhất cho codebase sống lâu dài.
Bạn muốn xác thực ở thời điểm biên dịch nhưng thích raw SQL hơn? → SQLx. Có toàn bộ độ an toàn mà không cần học DSL.
Bạn cần query động, quan hệ và ORM async hiện đại? → SeaORM 2.0. Đặc biệt nếu bạn đến từ Django hay Rails.
Lựa chọn mặc định cho dự án mới? → Thường tôi bắt đầu với Diesel. Trừ khi có lý do khác. Độ an toàn lúc compile đã cứu tôi quá nhiều lần.
Sự thật hơi khó chịu
Có một điều mà không ai trong cộng đồng Rust muốn thừa nhận: với phần lớn dự án, dùng cái nào trong số này cũng sẽ ổn.
Tất cả đều được duy trì tốt. Tất cả đều ngăn SQL injection. Tất cả đều làm việc với những DB mà chúng nhắm tới (trong phạm vi riêng của từng cái). Khác biệt chỉ lộ ra ở vùng rìa, mà đa số chúng ta thì không sống ở vùng rìa đó.
Hãy chọn thứ hợp với cách não bạn vận hành. Nếu bạn tư duy bằng SQL, hãy dùng SQLx. Nếu bạn muốn trình biên dịch chăm sóc cho mình, hãy dùng Diesel. Nếu bạn muốn cảm giác như ORM mà mình đã quen, hãy dùng SeaORM. Nếu là SQLite, hãy dùng Rusqlite.
Và thôi nghiên cứu đi, bắt đầu build đi.
Chưa có bình luận nào.