Sản phẩm
sqlite-utils 4.0 ra mắt: Hỗ trợ di chuyển lược đồ cơ sở dữ liệu mạnh mẽ
(giờ Việt Nam)
Tóm tắt AI
Phiên bản sqlite-utils 4.0 mang đến tính năng di chuyển lược đồ (schema migrations), giao dịch lồng nhau và hỗ trợ khóa ngoại phức hợp, giúp việc quản lý cơ sở dữ liệu SQLite trở nên linh hoạt và chuyên nghiệp hơn.
Bản dịch AI
Ngày 7 tháng 7 năm 2026
Sáng nay, tôi đã phát hành sqlite-utils 4.0, bản phát hành thứ 124 của dự án này và là lần nâng cấp phiên bản chính đầu tiên kể từ bản 3.0 vào tháng 11 năm 2020. Ngoài một số thay đổi nhỏ nhưng đáng kể gây phá vỡ tương thích (được mô tả trong hướng dẫn nâng cấp này), phiên bản này giới thiệu ba tính năng chính: di chuyển cơ sở dữ liệu (database migrations), giao dịch lồng nhau (nested transactions - thông qua phương thức db.atomic() mới) và hỗ trợ khóa ngoại phức hợp (compound foreign keys).
Di chuyển lược đồ cơ sở dữ liệu bằng sqlite-utils
Di chuyển lược đồ (schema migrations) xác định một chuỗi các thay đổi cần thực hiện đối với cơ sở dữ liệu SQLite, cùng với một cơ chế để theo dõi những thay đổi nào đã được áp dụng và thực hiện các thay đổi đang chờ xử lý.
Các di chuyển được định nghĩa trong các tệp Python sử dụng thư viện Python sqlite-utils, bao gồm phương thức table.transform() mạnh mẽ, cung cấp các khả năng thay đổi bảng nâng cao mà câu lệnh ALTER TABLE của SQLite không hỗ trợ.
(table.transform() triển khai mô hình được tài liệu của SQLite khuyến nghị—tạo một bảng tạm thời mới với lược đồ mới, sao chép dữ liệu sang, sau đó xóa bảng cũ và đổi tên bảng tạm thời thành tên bảng cũ.)
Dưới đây là ví dụ về tệp di chuyển tạo một bảng có tên là creatures, thêm một cột bổ sung vào bước thứ hai, sau đó thay đổi kiểu dữ liệu của hai cột trong bước thứ ba:
Lưu tệp đó dưới tên migrations.py và chạy nó với một cơ sở dữ liệu mới như sau:
Sau đó, nếu bạn kiểm tra lược đồ của cơ sở dữ liệu đó:
Bạn sẽ thấy SQL này:
Bảng _sqlite_migrations được sử dụng để theo dõi các hàm di chuyển nào đã được chạy. Bảng creatures ở trên là lược đồ sau khi cả ba lần di chuyển đã được áp dụng.
Để xem danh sách các di chuyển, bao gồm cả những di chuyển đang chờ xử lý và đã áp dụng, hãy chạy lệnh này:
Đầu ra:
Nếu bạn không chỉ định tệp di chuyển, lệnh sqlite-utils migrate data.db sẽ quét thư mục hiện tại và các thư mục con để tìm các tệp có tên migrations.py và áp dụng bất kỳ phiên bản Migrations() nào mà nó tìm thấy trong đó.
Bạn cũng có thể thực thi các di chuyển từ mã Python bằng phương thức migrations.apply(db), điều này rất hữu ích để xây dựng các công cụ tự quản lý lược đồ cơ sở dữ liệu của riêng chúng qua nhiều phiên bản. Công cụ LLM của riêng tôi đã sử dụng một phiên bản của mô hình này trong vài năm nay, như được hiển thị trong llm/embeddings_migrations.py.
Các công trình trước đây
Triển khai yêu thích của tôi về mô hình này vẫn là Django’s Migrations, được phát triển bởi Andrew Godwin dựa trên dự án trước đó của anh ấy là South. Một sự thật thú vị: Andrew, Russ Keith-Magee và tôi đã trình bày các phương pháp tiếp cận cạnh tranh của chúng tôi về di chuyển lược đồ cho Django tại hội thảo Schema Evolution ở sự kiện DjangoCon đầu tiên vào năm 2008! Nỗ lực của tôi có tên là dmigrations, được phát triển cùng với một nhóm tại Global Radio ở London.
Các di chuyển của Django có thể được tạo tự động từ các định nghĩa mô hình và bao gồm khả năng hoàn tác (roll back) về phiên bản trước. Cách tiếp cận của sqlite-utils cố tình đơn giản hơn: không giống như Django, sqlite-utils khuyến khích tạo bảng theo lập trình thay vì sử dụng ORM định nghĩa mô hình, vì vậy không có gì để chúng tôi có thể sử dụng để tự động tạo các di chuyển.
Tôi quyết định bỏ qua tính năng hoàn tác, vì theo kinh nghiệm của tôi, đây là tính năng hiếm khi được sử dụng. Với một dự án SQLite, một cách dễ dàng để thực hiện hoàn tác là tạo một bản sao tệp cơ sở dữ liệu của bạn trước khi áp dụng các di chuyển!
Di chuyển từ sqlite-migrate
Thiết kế của các di chuyển trong sqlite-utils đã có từ ba năm trước—tôi đã phát hành nó dưới dạng một gói riêng biệt có tên là sqlite-migrate, nhưng nó chưa bao giờ vượt qua giai đoạn bản thử nghiệm (beta).
Tôi đã sử dụng gói đó ở đủ nhiều nơi để tự tin vào thiết kế của nó, vì vậy tôi quyết định nâng cấp nó thành một tính năng của sqlite-utils để cung cấp mặc định cho tất cả các công cụ khác trong hệ sinh thái sqlite-utils/Datasette/LLM đang phát triển.
Tôi đã thực hiện bản phát hành cuối cùng của sqlite-migrate, chuyển nó sang phụ thuộc vào sqlite-utils>=4 và thay thế tệp __init__.py bằng nội dung sau:
Bất kỳ dự án hiện có nào phụ thuộc vào sqlite-migrate sẽ tiếp tục hoạt động mà không cần thay đổi.
Mọi thứ khác trong sqlite-utils 4.0
Dưới đây là ghi chú phát hành cho phiên bản này, với một số chú thích đi kèm:
Bản phát hành 4.0 bao gồm một số bản sửa lỗi nhỏ không tương thích ngược (do đó mới có việc tăng số phiên bản chính) và giới thiệu ba tính năng mới quan trọng:
Tôi coi các di chuyển là tính năng mới đặc trưng, đó là lý do cho bài đăng trên blog này.
sqlite-utils từ lâu đã có mối quan hệ phức tạp với các giao dịch cơ sở dữ liệu, một phần vì khi tôi bắt đầu thiết kế thư viện này vào năm 2018, tôi vẫn chưa hiểu rõ cách chúng hoạt động trong chính SQLite.
Việc thêm các di chuyển vào thư viện cốt lõi khiến tôi quyết tâm giải quyết vấn đề này, vì các giao dịch giúp hệ thống di chuyển an toàn hơn nhiều và dễ hiểu hơn.
Cuối cùng, tôi đã xây dựng tính năng này xung quanh trình quản lý ngữ cảnh db.atomic() trông như thế này:
SQLite hỗ trợ Savepoints, và kết quả là db.atomic() có thể được lồng vào nhau để thực hiện các giao dịch bên trong giao dịch. Nó khá hay!
Điều này xảy ra khi tôi yêu cầu một tác nhân lập trình (coding agent) xem xét tất cả các vấn đề và PR đang mở để tìm những thứ nên được đưa vào bản phát hành 4.0 vì chúng sẽ gây ra thay đổi phá vỡ nếu tôi thêm vào sau này, và nó đã xác định chính xác rằng khóa ngoại phức hợp chính là loại tính năng đó.
Tôi bắt đầu với một thay đổi phá vỡ đối với phương thức nội quan table.foreign_keys, sau đó quyết định xem liệu Claude Fable 5 có thể xử lý công việc phức tạp hơn là tích hợp việc tạo khóa ngoại phức hợp vào thư viện hay không. Thiết kế API mà nó giúp tạo ra cảm thấy hoàn toàn phù hợp với tôi—nhất quán với cách phần còn lại của thư viện đã hoạt động.
Các thay đổi đáng chú ý khác bao gồm:
Đây là thay đổi đầu tiên thúc đẩy tôi cân nhắc việc tăng phiên bản 4.0 gây phá vỡ tương thích. Tôi đã xây dựng tính năng này để hỗ trợ sqlite-chronicle, sử dụng các trình kích hoạt (triggers) để theo dõi các hàng trong bảng đã được chèn, cập nhật hoặc xóa.
Có lẽ đây là thay đổi phá vỡ gây gián đoạn nhất—tôi đã phải cập nhật một vài nơi trong mã của chính mình để chuyển từ db.query() sang db.execute() do kết quả của thay đổi này.
Cờ sqlite-utils insert data.db creatures creatures.csv --detect-types là một bổ sung sau này để cho phép các kiểu cột (text, integer, real) được tự động phát hiện dựa trên dữ liệu trong tệp CSV. Nó nên là mặc định, và việc phát hành bản 4.0 cho phép tôi thực hiện điều đó.
Vấn đề cũ nhất được giải quyết bởi bản phát hành này—lỗi cơ bản đã được mở (bởi tôi) vào tháng 10 năm 2020.
Xem Nâng cấp từ 3.x lên 4.0 để biết chi tiết về các thay đổi không tương thích ngược.
Bài viết được AI dịch và tổng hợp tự động từ Simon Willison Blog. Liên kết bài gốc ở phía trên. AIHOT.vn luôn dẫn nguồn đầy đủ — nếu bạn thấy điểm cần chỉnh sửa, hãy gửi ý kiến tại trang phản hồi.