Thiết kế Trình kích hoạt T-SQL của Microsoft
Trong những trường hợp khi xây dựng một dự án liên quan đến giao diện người dùng Access và phần phụ trợ của SQL Server, chúng tôi gặp phải câu hỏi này. Chúng ta có nên sử dụng một trình kích hoạt cho một cái gì đó không? Thiết kế trình kích hoạt SQL Server cho ứng dụng Access có thể là một giải pháp nhưng chỉ sau khi đã cân nhắc kỹ lưỡng. Đôi khi điều này được đề xuất như một cách để giữ logic nghiệp vụ trong cơ sở dữ liệu, thay vì ứng dụng. Thông thường, tôi thích có logic nghiệp vụ được xác định càng gần với cơ sở dữ liệu càng tốt. Vì vậy, kích hoạt có phải là giải pháp chúng tôi muốn cho giao diện người dùng Access của mình không?
Tôi nhận thấy rằng việc viết mã trình kích hoạt SQL đòi hỏi phải cân nhắc thêm và nếu không cẩn thận, chúng ta có thể gặp phải một mớ hỗn độn lớn hơn chúng ta bắt đầu. Bài viết nhằm mục đích đề cập đến tất cả các cạm bẫy và kỹ thuật mà chúng tôi có thể sử dụng để đảm bảo rằng khi chúng tôi xây dựng cơ sở dữ liệu với các trình kích hoạt, chúng sẽ hoạt động vì lợi ích của chúng tôi, thay vì chỉ thêm phức tạp vì phức tạp.
Hãy xem xét các quy tắc…
Quy tắc số 1:Không sử dụng trình kích hoạt!
Nghiêm túc. Nếu bạn tìm cách kích hoạt điều đầu tiên vào buổi sáng, thì bạn sẽ hối hận vào ban đêm. Vấn đề lớn nhất với trình kích hoạt nói chung là chúng có thể làm xáo trộn logic kinh doanh của bạn một cách hiệu quả và can thiệp vào các quy trình không cần trình kích hoạt. Tôi đã thấy một số đề xuất để tắt trình kích hoạt khi bạn đang tải hàng loạt hoặc điều gì đó tương tự. Tôi khẳng định rằng đây là một mùi mã lớn. Bạn không nên sử dụng trình kích hoạt nếu nó phải được bật hoặc tắt có điều kiện.
Theo mặc định, trước tiên chúng ta nên viết các thủ tục hoặc dạng xem được lưu trữ. Đối với hầu hết các tình huống, họ sẽ thực hiện công việc tốt. Đừng thêm phép thuật ở đây.
Vậy tại sao lại có bài viết về trigger?
Bởi vì kích hoạt có công dụng của chúng. Chúng ta cần nhận biết khi nào chúng ta nên sử dụng các trigger. Chúng ta cũng cần viết chúng theo cách giúp chúng ta nhiều hơn là làm tổn thương chúng ta.
Quy tắc số 2:Tôi có thực sự cần trình kích hoạt không?
Về lý thuyết, các bộ kích hoạt nghe rất hay. Họ cung cấp cho chúng tôi một mô hình dựa trên sự kiện để quản lý các thay đổi ngay sau khi chúng được sửa đổi. Nhưng nếu tất cả những gì bạn cần là xác thực một số dữ liệu hoặc đảm bảo rằng một số cột ẩn hoặc bảng ghi nhật ký được điền…. Tôi nghĩ rằng bạn sẽ thấy rằng một quy trình được lưu trữ thực hiện công việc hiệu quả hơn và loại bỏ khía cạnh kỳ diệu. Hơn nữa, viết một thủ tục được lưu trữ rất dễ kiểm tra; chỉ cần thiết lập một số dữ liệu giả và chạy quy trình được lưu trữ, xác minh kết quả là những gì bạn mong đợi. Tôi hy vọng bạn đang sử dụng khung thử nghiệm như tSQLt.
Và điều quan trọng cần lưu ý là sử dụng các ràng buộc cơ sở dữ liệu thường hiệu quả hơn so với trình kích hoạt. Vì vậy, nếu bạn chỉ cần xác nhận rằng một giá trị là hợp lệ trong một bảng khác, hãy sử dụng ràng buộc khóa ngoại. Việc xác thực rằng một giá trị nằm trong phạm vi nhất định sẽ gọi một ràng buộc kiểm tra. Đó phải là lựa chọn mặc định của bạn cho những loại xác thực đó.
Vậy khi nào chúng ta thực sự cần một trình kích hoạt?
Nó tóm tắt các trường hợp mà bạn thực sự muốn logic nghiệp vụ nằm trong lớp SQL. Có thể do bạn có nhiều ứng dụng khách trong các ngôn ngữ lập trình khác nhau đang thực hiện chèn / cập nhật vào bảng. Sẽ rất lộn xộn nếu sao chép logic nghiệp vụ trên từng khách hàng bằng ngôn ngữ lập trình tương ứng của họ và điều này cũng đồng nghĩa với việc có nhiều lỗi hơn. Đối với các trường hợp không thực tế để tạo lớp trung gian, trình kích hoạt là cách hành động tốt nhất của bạn để thực thi quy tắc kinh doanh không thể được thể hiện dưới dạng ràng buộc.
Để sử dụng một ví dụ cụ thể cho Access. Giả sử chúng ta muốn thực thi logic nghiệp vụ khi sửa đổi dữ liệu thông qua ứng dụng. Có thể chúng ta có nhiều biểu mẫu nhập dữ liệu liên kết với một bảng hoặc có thể chúng ta cần hỗ trợ biểu mẫu nhập dữ liệu phức tạp trong đó nhiều bảng cơ sở phải tham gia vào việc chỉnh sửa. Có thể biểu mẫu nhập dữ liệu cần hỗ trợ các mục nhập không chuẩn hóa mà sau đó chúng tôi sẽ biên soạn lại thành dữ liệu chuẩn hóa. Trong tất cả những trường hợp đó, chúng tôi chỉ có thể viết mã VBA nhưng điều đó có thể khó duy trì và xác thực cho mọi trường hợp. Trình kích hoạt giúp chúng ta chuyển logic ra khỏi VBA và sang T-SQL. Logic nghiệp vụ lấy dữ liệu làm trung tâm thường được đặt gần với dữ liệu nhất có thể.
Quy tắc số 3:Trình kích hoạt phải dựa trên bộ, không phải dựa trên hàng
Cho đến nay, lỗi phổ biến nhất được thực hiện với trình kích hoạt là làm cho nó chạy trên các hàng. Thường thì chúng ta thấy mã tương tự như sau:
- Mã quảng cáo! Không sử dụng! TẠO TRIGGER dbo.SomeTriggerON dbo.SomeTable SAU KHI INSERTASBEGIN DECLARE @NewTotal money; DECLARE @NewID int; CHỌN TOP 1 @NewID =SalesOrderID, @NewTotal =SalesAmount FROM được chèn vào; CẬP NHẬT dbo.SalesOrder SET OrderTotal =OrderTotal + @NewTotal WHERE SalesOrderID =@SalesOrderIDEND;
Món quà chỉ là sự thật rằng đã có CHỌN TOP 1 khỏi một bảng đã chèn. Điều này sẽ chỉ hoạt động miễn là chúng ta chỉ chèn một hàng. Nhưng khi nó có nhiều hơn một hàng, thì điều gì sẽ xảy ra với những hàng không may mắn đứng thứ 2 và sau đó? Chúng tôi có thể cải thiện điều đó bằng cách làm điều gì đó tương tự như sau:
- Vẫn là mã không hợp lệ! Không sử dụng! TẠO TRIGGER dbo.SomeTriggerON dbo.SomeTable SAU KHI CẬP NHẬT MERGE INSERTASBEGIN MERGE VÀO dbo.>Điều này hiện dựa trên thiết lập và do đó đã được cải thiện nhiều nhưng điều này vẫn còn các vấn đề khác mà chúng ta sẽ thấy trong một vài quy tắc tiếp theo…
Quy tắc số 4:Sử dụng chế độ xem thay thế.
Một khung nhìn có thể có một trình kích hoạt được gắn vào nó. Điều này mang lại cho chúng tôi lợi thế là tránh được các vấn đề liên quan đến trình kích hoạt bảng. Chúng tôi có thể dễ dàng nhập hàng loạt dữ liệu sạch vào bảng mà không cần phải tắt bất kỳ trình kích hoạt nào. Hơn nữa, một trình kích hoạt trên chế độ xem làm cho nó trở thành một lựa chọn tham gia rõ ràng. Nếu bạn có các chức năng liên quan đến bảo mật hoặc các quy tắc kinh doanh đòi hỏi phải chạy các trình kích hoạt, bạn có thể trực tiếp thu hồi các quyền trên bảng và do đó chuyển chúng sang chế độ xem mới thay thế. Điều đó đảm bảo rằng bạn sẽ xem qua dự án và lưu ý những nơi cần cập nhật bảng để sau đó bạn có thể theo dõi chúng để tìm bất kỳ lỗi hoặc sự cố nào có thể xảy ra.
Nhược điểm là một dạng xem chỉ có thể có bộ kích hoạt INSTEAD OF được đính kèm, có nghĩa là bạn phải tự mình thực hiện các sửa đổi tương đương một cách rõ ràng trên bảng cơ sở trong bộ kích hoạt. Tuy nhiên, tôi có xu hướng nghĩ tốt hơn theo cách đó vì nó cũng đảm bảo rằng bạn biết chính xác việc sửa đổi sẽ như thế nào và do đó cung cấp cho bạn mức kiểm soát giống như mức bạn thường có trong một quy trình được lưu trữ.
Quy tắc số 5:Trình kích hoạt phải đơn giản.
Hãy nhớ nhận xét về gỡ lỗi và thử nghiệm một thủ tục được lưu trữ? Điều tốt nhất mà chúng ta có thể làm cho chính mình là giữ logic nghiệp vụ trong một quy trình được lưu trữ và thay vào đó, trình kích hoạt sẽ gọi nó. Bạn không bao giờ nên viết logic nghiệp vụ trực tiếp vào trình kích hoạt; đang đổ bê tông hiệu quả vào cơ sở dữ liệu. Bây giờ nó đã bị đóng băng về hình dạng và có thể gặp vấn đề để kiểm tra logic một cách đầy đủ. Bộ khai thác thử nghiệm của bạn bây giờ phải liên quan đến một số sửa đổi đối với bảng cơ sở. Điều này không tốt cho việc viết các bài kiểm tra đơn giản và lặp lại. Điều này sẽ phức tạp nhất vì trình kích hoạt của bạn phải được phép:
TẠO TRIGGER [dbo]. [SomeTrigger] ON [dbo]. [SomeView] INSTEAD OF INSERT, UPDATE, DELETEASBEGIN DECLARE @SomeIDs AS SomeIDTableType - Thực hiện hợp nhất vào bảng cơ sở MERGE INTO dbo. AS i ON t. Đã chèn OUTPUT.SomeID INTO @SomeIDs (SomeID); DELETE FROM dbo.SomeTable OUTPUT đã bị xóa.SomeID INTO @SomeIDs (SomeID) WHERE TỒN TẠI (CHỌN NULL TỪ đã xóa AS d WHERE d.SomeID =SomeTable.SomeID) VÀ KHÔNG TỒN TẠI (CHỌN ĐẦY ĐỦ TỪ được chèn AS i WHERE i.SomeID =SomeTable. SomeID); EXEC dbo.uspUpdateSomeStuff @SomeIDs; END;Phần đầu tiên của trình kích hoạt về cơ bản là thực hiện các sửa đổi thực tế trên bảng cơ sở vì nó là trình kích hoạt INSTEAD OF, vì vậy chúng tôi phải thực hiện tất cả các sửa đổi sẽ khác nhau tùy thuộc vào các bảng mà chúng tôi cần quản lý. Cần nhấn mạnh rằng các sửa đổi chủ yếu phải là nguyên văn. Chúng tôi không tính toán lại hoặc biến đổi bất kỳ dữ liệu nào. Chúng tôi lưu tất cả công việc bổ sung đó vào cuối, nơi tất cả những gì chúng tôi đang làm bên trong trình kích hoạt là điền vào danh sách các bản ghi đã được trình kích hoạt sửa đổi và cung cấp cho một thủ tục được lưu trữ bằng cách sử dụng tham số có giá trị bảng. Lưu ý rằng chúng tôi thậm chí không xem xét hồ sơ nào đã được thay đổi cũng như cách nó được thay đổi. Tất cả những gì có thể được thực hiện trong quy trình được lưu trữ.
Quy tắc số 6:Trình kích hoạt phải được định hướng bất cứ khi nào có thể.
Nói chung, các trình kích hoạt PHẢI hãy vững vàng. Điều này áp dụng cho dù đó là trình kích hoạt dựa trên bảng hay dựa trên chế độ xem. Nó đặc biệt áp dụng cho những người cần sửa đổi dữ liệu trên các bảng cơ sở mà từ đó trình kích hoạt đang theo dõi. Tại sao? Bởi vì nếu con người đang sửa đổi dữ liệu sẽ được trình kích hoạt chọn, họ có thể nhận ra mình đã mắc lỗi, chỉnh sửa lại hoặc có thể chỉ cần chỉnh sửa cùng một bản ghi và lưu nó 3 lần. Họ sẽ không vui nếu họ nhận thấy rằng các báo cáo thay đổi mỗi khi họ thực hiện một chỉnh sửa mà không được cho là sửa đổi kết quả đầu ra cho báo cáo.
Nói rõ hơn, bạn có thể thử và tối ưu hóa trình kích hoạt bằng cách làm điều gì đó tương tự như sau:
WITH SourceData AS (SELECT OrderID, SUM (SalesAmount) AS NewSaleTotal TỪ GROUP BY OrderID được chèn vào) MERGE INTO dbo.SalesOrder AS oUSING SourceData AS dON o.OrderID =d.OrderIDWHEN MATCHED SAU ĐÓ CẬP NHẬT ĐẶT HÀNG o.OrderTotal =o. + d.NewSaleTotal;Chúng ta có thể tránh tính lại tổng mới bằng cách chỉ xem lại các hàng đã sửa đổi trong bảng đã chèn, phải không? Nhưng khi người dùng chỉnh sửa hồ sơ để sửa lỗi đánh máy trong tên của khách hàng, điều gì sẽ xảy ra? Chúng tôi kết thúc với một tổng số không có thật và trình kích hoạt hiện đang hoạt động chống lại chúng tôi.
Bây giờ, bạn sẽ thấy lý do tại sao quy tắc số 4 giúp chúng ta bằng cách chỉ đẩy các khóa chính vào quy trình được lưu trữ, thay vì cố gắng chuyển bất kỳ dữ liệu nào vào quy trình được lưu trữ hoặc thực hiện trực tiếp bên trong trình kích hoạt như mẫu đã làm .
Thay vào đó, chúng tôi muốn có một số mã tương tự như mã này trong một thủ tục được lưu trữ:
TẠO QUY TRÌNH Dbo.uspUpdateSalesTotal (@SalesOrders SalesOrderTableType ĐÃ SN SÀNG) BẮT ĐẦU VỚI SourceData AS (SELECT s.OrderID, SUM (s.SalesAmount) AS NewSaleTotal FROM dbo.SalesOrder AS s WHERE .SalesOrderID =s.SalesOrderID) GROUP BY OrderID) MERGE INTO dbo.SalesOrder AS o SỬ DỤNG SourceData AS d ON o.OrderID =d.OrderID KHI ĐƯỢC PHÉP THEO THÌ CẬP NHẬT O.OrderTotal =d.NewSaleTotal; END;Bằng cách sử dụng @SalesOrders, chúng tôi vẫn có thể chỉ cập nhật có chọn lọc các hàng bị ảnh hưởng bởi trình kích hoạt và chúng tôi cũng có thể tính toán lại tổng thể mới và biến nó thành tổng mới. Vì vậy, ngay cả khi người dùng đánh máy tên khách hàng và chỉnh sửa nó, mỗi lần lưu sẽ mang lại cùng một kết quả cho hàng đó.
Quan trọng hơn, cách tiếp cận này cũng cung cấp cho chúng tôi một cách dễ dàng để tính tổng. Giả sử chúng ta phải nhập hàng loạt và nhập không chứa tổng số, vì vậy chúng ta phải tự tính toán. Chúng ta có thể viết thủ tục đã lưu trữ để ghi trực tiếp vào bảng. Sau đó, chúng tôi có thể gọi quy trình được lưu trữ ở trên chuyển ID từ quá trình nhập và tất cả chúng tôi đều ổn. Do đó, logic mà chúng tôi sử dụng không bị ràng buộc trong trình kích hoạt đằng sau chế độ xem. Điều đó hữu ích khi logic là không cần thiết đối với quá trình nhập hàng loạt mà chúng tôi đang thực hiện.
Nếu bạn thấy mình đang gặp vấn đề trong việc tạo ra iđêan kích hoạt, thì đó là một dấu hiệu mạnh mẽ cho thấy bạn có thể cần phải sử dụng một quy trình được lưu trữ thay thế và gọi nó trực tiếp từ ứng dụng của bạn thay vì dựa vào trình kích hoạt. Một ngoại lệ đáng chú ý đối với quy tắc này là khi trình kích hoạt chủ yếu có nghĩa là trình kích hoạt kiểm tra. Trong trường hợp này, bạn muốn ghi một hàng mới vào bảng kiểm tra cho mỗi lần chỉnh sửa, bao gồm tất cả lỗi chính tả mà người dùng mắc phải. Điều này là OK vì trong trường hợp đó, không có thay đổi nào đối với dữ liệu mà người dùng đang tương tác. Từ POV của người dùng, kết quả vẫn giống nhau. Nhưng bất cứ khi nào trình kích hoạt cần xử lý cùng một dữ liệu mà người dùng đang làm việc, sẽ tốt hơn nhiều khi nó là ý tưởng.
Kết thúc
Hy vọng rằng đến giờ, bạn có thể thấy việc thiết kế một trình kích hoạt hoạt động tốt có thể khó khăn hơn như thế nào. Vì lý do đó, bạn nên cẩn thận xem xét liệu bạn có thể tránh nó hoàn toàn và sử dụng các lệnh gọi trực tiếp với thủ tục được lưu trữ hay không. Nhưng nếu bạn đã kết luận rằng bạn phải có trình kích hoạt để quản lý các sửa đổi được thực hiện thông qua lượt xem, tôi hy vọng rằng các quy tắc sẽ giúp ích cho bạn. Làm cho bộ kích hoạt dựa trên bộ kích hoạt đủ dễ dàng với một số điều chỉnh. Làm cho nó trở nên lý tưởng thường đòi hỏi nhiều suy nghĩ hơn về cách bạn sẽ triển khai các thủ tục đã lưu trữ của mình.
Nếu bạn có thêm bất kỳ đề xuất hoặc quy tắc nào để chia sẻ, hãy bỏ qua phần nhận xét!