Tôi đã suy nghĩ về điều đó trong một thời gian và chỉ có thể nghĩ ra hai cách để làm điều này. Cả hai đều có thể hoạt động hoàn toàn trong suốt khi được tạo thành một mô hình / lớp dữ liệu trừu tượng.
Nhân tiện, có một triển khai cho dữ liệu bảng "có thể thay đổi được" trong học thuyết ánh xạ ORM. Hãy xem ví dụ này trong tài liệu của họ . Có thể điều đó phù hợp với nhu cầu của bạn, nhưng nó không phù hợp với tôi. Có vẻ như nó sẽ xóa tất cả dữ liệu lịch sử khi bản ghi gốc bị xóa, khiến bản sửa đổi không thực sự an toàn.
Tùy chọn A:có một bản sao của mỗi bảng để giữ dữ liệu sửa đổi
Giả sử bạn có một bảng liên hệ đơn giản:
CREATE TABLE contact (
id INT NOT NULL auto_increment,
name VARCHAR(255),
firstname VARCHAR(255),
lastname VARCHAR(255),
PRIMARY KEY (id)
)
Bạn sẽ tạo một bản sao của bảng đó và thêm dữ liệu sửa đổi:
CREATE TABLE contact_revisions (
id INT NOT NULL,
name VARCHAR(255),
firstname VARCHAR(255),
lastname VARCHAR(255),
revision_id INT auto_increment,
type ENUM('INSERT', 'UPDATE', 'DELETE') NOT NULL,
change_time DEFAULT current_timestamp,
PRIMARY KEY(revision_id)
)
Theo dõi INSERT
và UPDATE
sử dụng AFTER
gây nên. Trên mỗi bản sửa đổi dữ liệu mới trong bản gốc, hãy chèn một bản sao của dữ liệu mới vào bảng sửa đổi và đặt type
sửa đổi đúng cách.
Để ghi một DELETE
xét lại an toàn, bạn cũng phải chèn một hàng mới trong bảng lịch sử! Đối với điều này, bạn nên sử dụng BEFORE DELETE
kích hoạt và lưu trữ các giá trị mới nhất trước khi chúng bị xóa. Nếu không, bạn sẽ phải xóa mọi NOT NULL
trong cả bảng lịch sử.
Một số lưu ý quan trọng liên quan đến việc triển khai này
- Đối với bảng lịch sử, bạn phải thả mọi
UNIQUE KEY
(tại đây:PRIMARY KEY
) từ bảng sửa đổi vì bạn sẽ có cùng một khóa nhiều lần cho mỗi lần sửa đổi dữ liệu. - Khi bạn
ALTER
lược đồ và dữ liệu trong bảng gốc thông qua bản cập nhật (ví dụ:cập nhật phần mềm), bạn phải đảm bảo áp dụng cùng một dữ liệu hoặc các chỉnh sửa giản đồ cho bảng lịch sử và dữ liệu của nó. Nếu không, bạn sẽ gặp rắc rối khi hoàn nguyên về bản sửa đổi cũ hơn của bộ hồ sơ. - Trong triển khai thế giới thực, bạn muốn biết người dùng nào đã sửa đổi dữ liệu. Để đảm bảo an toàn một cách tạm thời, một bản ghi người dùng sẽ không bao giờ bị xóa khỏi bảng người dùng. Bạn chỉ nên đặt tài khoản bị vô hiệu hóa bằng một lá cờ.
- Thông thường, một hành động của người dùng liên quan đến nhiều bảng. Trong triển khai thế giới thực, bạn cũng sẽ phải theo dõi những thay đổi nào trong nhiều bảng thuộc về một giao dịch người dùng duy nhất và theo thứ tự nào. Trong trường hợp sử dụng thực tế, bạn sẽ muốn hoàn nguyên tất cả các thay đổi của một giao dịch cùng nhau, theo thứ tự ngược lại. Điều đó sẽ yêu cầu một bảng sửa đổi bổ sung theo dõi người dùng và giao dịch, đồng thời giữ mối quan hệ lỏng lẻo với tất cả các bản sửa đổi riêng lẻ đó trong bảng lịch sử.
Lợi ích:
- hoàn toàn trong cơ sở dữ liệu, độc lập với mã ứng dụng. (tốt, không phải khi việc theo dõi các giao dịch của người dùng là quan trọng. Điều đó sẽ yêu cầu một số logic bên ngoài phạm vi của một truy vấn)
- tất cả dữ liệu đều ở định dạng ban đầu, không có chuyển đổi kiểu ngầm định.
- hiệu suất tốt trên tìm kiếm trong các bản sửa đổi
- khôi phục dễ dàng. Chỉ cần thực hiện một
INSERT .. ON DUPLICATE KEY UPDATE ..
trên bảng gốc, sử dụng dữ liệu từ bản sửa đổi mà bạn muốn khôi phục.
Bằng khen:
- Khó triển khai thủ công.
- Khó (nhưng không phải là không thể) tự động hóa khi di chuyển cơ sở dữ liệu / cập nhật ứng dụng.
Như đã nêu ở trên, học thuyết versionable
làm một cái gì đó tương tự.
Tùy chọn B:có bảng nhật ký thay đổi trung tâm
lời nói đầu:thực hành không tốt, chỉ được hiển thị để minh họa cho giải pháp thay thế.
Cách tiếp cận này chủ yếu dựa vào logic ứng dụng, logic này nên được ẩn trong một lớp / mô hình dữ liệu.
Bạn có một bảng lịch sử trung tâm luôn theo dõi
- Ai đã làm
- khi nào
- sửa đổi, chèn hoặc xóa
- dữ liệu nào
- trong trường nào
- của bảng nào
Giống như trong cách tiếp cận khác, bạn cũng có thể muốn theo dõi những thay đổi dữ liệu riêng lẻ nào thuộc về một hành động / giao dịch của người dùng và theo thứ tự nào.
Lợi ích:
- không cần tiếp tục đồng bộ hóa với bảng gốc khi thêm trường vào bảng hoặc tạo bảng mới. nó mở rộng quy mô một cách minh bạch.
Bằng khen:
- phương pháp không tốt khi sử dụng một giá trị đơn giản =kho khóa trong cơ sở dữ liệu
- hiệu suất tìm kiếm kém do các chuyển đổi kiểu ngầm định
- có thể làm chậm hiệu suất tổng thể của ứng dụng / cơ sở dữ liệu, khi bảng lịch sử trung tâm trở thành nút cổ chai do khóa ghi (điều này chỉ áp dụng cho các công cụ cụ thể có khóa bảng, tức là MyISAM)
- Việc triển khai khôi phục lại khó hơn nhiều
- có thể xảy ra lỗi chuyển đổi dữ liệu / mất độ chính xác do chuyển đổi kiểu ngầm định
- không theo dõi các thay đổi khi bạn truy cập trực tiếp vào cơ sở dữ liệu ở đâu đó trong mã của bạn thay vì sử dụng mô hình / lớp dữ liệu của bạn và quên rằng trong trường hợp này, bạn phải ghi vào nhật ký sửa đổi theo cách thủ công. Có thể là một vấn đề lớn khi làm việc trong nhóm với các lập trình viên khác.
Kết luận:
- Tùy chọn B có thể rất tiện dụng cho các ứng dụng nhỏ như một "lần ghé thăm" đơn giản khi nó chỉ để ghi nhật ký thay đổi.
- Nếu bạn muốn quay ngược thời gian và có thể dễ dàng so sánh sự khác biệt giữa phiên bản lịch sử 123 đến bản sửa đổi 125 và / hoặc hoàn nguyên về dữ liệu cũ, sau đó chọn Tùy chọn A là một con đường khó đi.