Thiết kế và thực hành để bảo vệ chống lại các mục nhập sai từ cơ sở dữ liệu


9

Một phần trong chương trình của tôi lấy dữ liệu từ nhiều bảng và cột trong cơ sở dữ liệu của tôi để xử lý. Một số cột có thể là null, nhưng trong bối cảnh xử lý hiện tại có lỗi.

Điều này "về mặt lý thuyết" sẽ không xảy ra, vì vậy nếu nó chỉ ra dữ liệu xấu hoặc lỗi trong mã. Các lỗi có mức độ nghiêm trọng khác nhau, tùy thuộc vào lĩnh vực nào null; tức là đối với một số trường, quá trình xử lý phải được dừng lại và ai đó đã thông báo, đối với những trường khác, việc xử lý sẽ được phép tiếp tục và chỉ cần thông báo cho ai đó.

Có bất kỳ nguyên tắc kiến ​​trúc hoặc thiết kế tốt để xử lý các mục hiếm nhưng có thể null?

Các giải pháp nên có thể thực hiện với Java nhưng tôi đã không sử dụng thẻ vì tôi nghĩ vấn đề này hơi khó hiểu về ngôn ngữ.


Một số suy nghĩ mà tôi đã có bản thân mình:

Sử dụng KHÔNG NULL

Dễ nhất là sử dụng ràng buộc KHÔNG NULL trong cơ sở dữ liệu.

Nhưng điều gì sẽ xảy ra nếu việc chèn dữ liệu ban đầu quan trọng hơn là bước xử lý sau này? Vì vậy, trong trường hợp chèn sẽ đặt một nullbảng vào (vì lỗi hoặc thậm chí là một số lý do hợp lệ), tôi sẽ không muốn chèn không thành công. Giả sử rằng nhiều phần khác của chương trình phụ thuộc vào dữ liệu được chèn, nhưng không phụ thuộc vào cột cụ thể này. Vì vậy, tôi muốn mạo hiểm lỗi trong bước xử lý hiện tại thay vì bước chèn. Đó là lý do tại sao tôi không muốn sử dụng ràng buộc KHÔNG NULL.

Hoàn toàn phụ thuộc vào NullPulumException

Tôi chỉ có thể sử dụng dữ liệu như thể tôi mong đợi nó luôn ở đó (và đó thực sự là trường hợp) và bắt các NPE kết quả ở mức thích hợp (ví dụ: quá trình xử lý mục nhập hiện tại dừng nhưng không phải toàn bộ tiến trình xử lý ). Đây là nguyên tắc "thất bại nhanh" và tôi thường thích nó. Nếu đó là một lỗi ít nhất tôi nhận được một NPE đã đăng nhập.

Nhưng sau đó tôi mất khả năng phân biệt giữa các loại dữ liệu bị thiếu. Ví dụ, đối với một số dữ liệu bị thiếu, tôi có thể loại bỏ nó, nhưng đối với những người khác, quá trình xử lý nên được dừng lại và thông báo cho quản trị viên.

Kiểm tra nulltrước mỗi lần truy cập và ném ngoại lệ tùy chỉnh

Các ngoại lệ tùy chỉnh sẽ cho phép tôi quyết định hành động chính xác dựa trên ngoại lệ, vì vậy đây có vẻ là cách để đi.

Nhưng nếu tôi quên kiểm tra nó ở đâu đó thì sao? Ngoài ra, sau đó tôi làm lộn xộn mã của mình bằng các kiểm tra null không bao giờ hoặc hiếm khi được mong đợi (và do đó chắc chắn không phải là một phần của luồng logic kinh doanh).

Nếu tôi chọn đi theo con đường này, mô hình nào phù hợp nhất cho cách tiếp cận?


Bất kỳ suy nghĩ và ý kiến ​​về cách tiếp cận của tôi đều được hoan nghênh. Ngoài ra các giải pháp tốt hơn dưới bất kỳ hình thức nào (mẫu, nguyên tắc, kiến ​​trúc tốt hơn về mã hoặc mô hình của tôi, v.v.).

Biên tập:

Có một ràng buộc khác, đó là tôi đang sử dụng ORM để thực hiện ánh xạ từ DB sang đối tượng kiên trì, do đó, kiểm tra null ở mức đó sẽ không hoạt động (vì các đối tượng tương tự được sử dụng trong các phần mà null không gây hại gì) . Tôi đã thêm điều này bởi vì các câu trả lời được cung cấp cho đến nay cả hai đều đề cập đến tùy chọn này.


5
"Một số cột có thể là null, nhưng trong bối cảnh xử lý hiện tại có lỗi. ... trong trường hợp phần chèn sẽ đặt null vào bảng, tôi sẽ không muốn phần chèn bị lỗi." Hai yêu cầu đó là mâu thuẫn. Không thể tìm ra giải pháp cho đến khi bạn thư giãn một trong hai điều kiện.
Kilian Foth

@KilianFoth Chà, thư giãn của tôi là lỗi trong bối cảnh "xử lý hiện tại" ít nghiêm trọng hơn so với khi chèn. Vì vậy, tôi chấp nhận các lỗi xử lý hiếm gặp, nhưng tôi muốn có một thiết kế mạnh mẽ tốt để xử lý chúng. Đó là lý do tại sao KHÔNG NULL, nếu không sẽ là một giải pháp tốt, thì không thể ở đây.
jhyot

1
Nếu bạn chấp nhận quá nhiều lỗi, người khởi tạo lỗi đó sẽ không bao giờ sửa chúng. Nếu các câu lệnh chèn lộn xộn của họ thành công, họ có động lực gì để sửa chữa mọi thứ? Bạn có cân nhắc mạnh mẽ không thất bại nhưng chấp nhận dữ liệu xấu?
Tulains Córdova

@ user61852 Tôi rõ ràng không chấp nhận lỗi nhưng muốn xử lý chúng một cách duyên dáng. Nuốt con trỏ null là ra khỏi câu hỏi. Ngoài ra, điều gì sẽ xảy ra nếu phần của tôi thực sự khách quan (như được xác định bởi doanh nghiệp) ít quan trọng hơn nhiều phần khác yêu cầu chèn để thành công nhưng không yêu cầu trường cụ thể này được đặt? Các phần chèn không bắt nguồn từ mục nhập của người dùng nơi tôi có thể buộc họ thêm giá trị, mà từ mã khác mà thiếu sót rất có thể là một lỗi (nhưng không đủ quan trọng để phá vỡ phần chèn).
jhyot

1
Đánh dấu chúng là KHÔNG NULL trong cơ sở dữ liệu sẽ là giải pháp tốt nhất, nếu một cột là null, thì mã sẽ cần xử lý trường hợp khi nó xảy ra, ngay cả khi nó không được mong đợi vì cơ chế lưu trữ cho phép.
Jon Raynor

Câu trả lời:


9

Tôi sẽ đặt các kiểm tra null trong mã ánh xạ của bạn, nơi bạn xây dựng đối tượng của mình từ tập kết quả. Điều đó đặt việc kiểm tra ở một nơi và sẽ không cho phép mã của bạn được xử lý nửa chừng trước khi xử lý một bản ghi trước khi gặp lỗi. Tùy thuộc vào cách hoạt động của luồng ứng dụng của bạn, bạn có thể muốn thực hiện ánh xạ tất cả các kết quả dưới dạng bước xử lý trước thay vì ánh xạ và xử lý từng bản ghi một lần.

Nếu bạn đang sử dụng ORM thì bạn sẽ phải thực hiện tất cả các kiểm tra null trước khi xử lý từng bản ghi. Tôi muốn giới thiệu một recordIsValid(recordData)phương thức -type, theo cách đó bạn có thể (một lần nữa) giữ tất cả logic kiểm tra null và logic xác thực khác ở một nơi. Tôi chắc chắn sẽ không xen kẽ các kiểm tra null với phần còn lại của logic xử lý của bạn.


Cảm ơn bạn, đó là cái nhìn sâu sắc tốt! Tôi thực sự đang sử dụng ORM, vì vậy kiểm tra ở cấp độ đó sẽ không hoạt động. Nhưng tôi cũng có một số ánh xạ tới các đối tượng miền thực từ các đối tượng bền vững. Tôi sẽ kiểm tra xem việc thực hiện ánh xạ và xác nhận trong bước tiền xử lý có khả thi hay không.
jhyot

Và nếu bạn chuyển ORM của bạn, thì sao? Tốt hơn là bảo vệ điều này tại nguồn (xem câu trả lời của Doc Brown).
Robbie Dee

@RobbieDee: Không nên quan trọng. Nếu bạn phải viết lại mã ánh xạ thì có kiểm tra null ở đó và bạn sửa đổi chúng như là một phần của việc viết lại hoặc bạn đã có một phương thức riêng để thực hiện kiểm tra null trên các đối tượng kinh doanh của bạn, do đó không cần viết lại. Và như Doc Brown ngụ ý, đôi khi điều quan trọng cần lưu ý là dữ liệu bị thiếu thay vì che đậy thực tế đó bằng một giá trị mặc định.
TMN

Điều đó sẽ xảy ra hơn nữa trong dòng chảy ETL. Bạn vẫn có nguy cơ nhân đôi nỗ lực theo cách này.
Robbie Dee

6

Nghe có vẻ như chèn null là một lỗi nhưng bạn sợ phải thực thi lỗi này khi chèn vì bạn không muốn mất dữ liệu. Tuy nhiên, nếu một trường không nên rỗng nhưng là, bạn đang mất dữ liệu . Do đó, giải pháp tốt nhất là đảm bảo rằng các trường null không bị lưu nhầm ngay từ đầu.

Để kết thúc này, thực thi rằng dữ liệu là chính xác trong một kho lưu trữ vĩnh viễn, có thẩm quyền cho dữ liệu đó, cơ sở dữ liệu. Làm như vậy bằng cách thêm các ràng buộc không null. Sau đó, mã của bạn có thể thất bại nhưng những lỗi này ngay lập tức thông báo cho bạn về các lỗi, cho phép bạn sửa các vấn đề đã khiến bạn mất dữ liệu. Bây giờ bạn có thể dễ dàng xác định lỗi, kiểm tra mã của bạn và kiểm tra nó hai lần. Bạn sẽ có thể sửa các lỗi dẫn đến mất dữ liệu và trong quá trình này, đơn giản hóa đáng kể việc xử lý dữ liệu xuôi dòng vì bạn sẽ không cần phải lo lắng về null.


2
Cảm ơn câu trả lời. Tôi đồng ý rằng giải pháp của bạn là cách phù hợp để thực hiện và bạn đã thực hiện chính xác. Các ràng buộc bên ngoài ảnh hưởng của tôi có thể gây khó khăn hoặc không thể (ví dụ: tài nguyên không có sẵn để kiểm tra hoặc để tự động kiểm tra mã hiện tại), nhưng tôi chắc chắn nên kiểm tra kỹ xem giải pháp này có thể hoạt động hay không trước khi thử các cách khác. Trong suy nghĩ ban đầu của tôi, tôi có thể giả định quá nhanh rằng tôi không thể khắc phục vấn đề tại nguồn.
jhyot

@jhyot Được rồi. Thật là bực bội khi bạn không thể làm mọi thứ theo cách sạch sẽ. Hy vọng rằng câu trả lời của tôi ít nhất hữu ích cho những người khác có vấn đề tương tự nhưng những người có khả năng tấn công vào nguyên nhân gốc thay vì dọn dẹp mớ hỗn độn sau thực tế.
Phục hồi lại

5

Liên quan đến câu này trong câu hỏi:

Điều này "về mặt lý thuyết" sẽ không xảy ra, vì vậy nếu nó chỉ ra dữ liệu xấu hoặc lỗi trong mã.

Tôi đã luôn đánh giá cao trích dẫn này (lịch sự của bài viết này ):

Tôi thấy thật buồn cười khi các lập trình viên mới làm việc tin rằng công việc chính của họ là ngăn chặn các chương trình bị sập. Tôi tưởng tượng cuộc tranh luận thất bại ngoạn mục này sẽ không hấp dẫn với một lập trình viên như vậy. Nhiều lập trình viên có kinh nghiệm nhận ra rằng mã chính xác là tuyệt vời, mã mà sự cố có thể sử dụng cải tiến, nhưng mã không chính xác mà không gặp sự cố là một cơn ác mộng khủng khiếp.

Về cơ bản: có vẻ như bạn đang tán thành Luật Postel , "hãy thận trọng trong những gì bạn gửi, hãy tự do trong những gì bạn chấp nhận". Mặc dù tuyệt vời về mặt lý thuyết, trong thực tế, "nguyên tắc mạnh mẽ" này dẫn đến phần mềm không mạnh mẽ , ít nhất là về lâu dài - và đôi khi cũng trong ngắn hạn. (So ​​sánh bài viết của Eric Allman Nguyên tắc mạnh mẽ được xem xét lại , đây là cách xử lý rất kỹ đối tượng, mặc dù chủ yếu tập trung vào các trường hợp sử dụng giao thức mạng.)

Nếu bạn có các chương trình chèn dữ liệu không chính xác vào cơ sở dữ liệu của mình, các chương trình đó bị hỏng và cần được sửa chữa . Việc vượt qua vấn đề chỉ cho phép nó tiếp tục trở nên tồi tệ hơn; đây là công nghệ phần mềm tương đương với việc cho phép người nghiện tiếp tục nghiện.

Tuy nhiên, nói một cách thực tế, đôi khi bạn cần phải cho phép hành vi "bị hỏng" tiếp tục, ít nhất là tạm thời, đặc biệt là một phần của quá trình chuyển đổi liền mạch từ trạng thái lỏng lẻo, bị hỏng sang trạng thái nghiêm ngặt, chính xác. Trong trường hợp đó, bạn muốn tìm cách cho phép các phần chèn không chính xác thành công, nhưng vẫn cho phép kho dữ liệu "chính tắc" luôn ở trạng thái chính xác . Có nhiều cách khác nhau để làm điều này:

  • Sử dụng trình kích hoạt cơ sở dữ liệu để chuyển đổi các phần chèn không đúng định dạng thành các phần chèn chính xác, ví dụ: bằng cách thay thế các giá trị bị thiếu / null bằng mặc định
  • Có các chương trình không chính xác chèn vào một bảng cơ sở dữ liệu riêng biệt được phép là "không chính xác" và có một quy trình được lên lịch riêng hoặc cơ chế khác để di chuyển dữ liệu đã sửa từ bảng đó vào kho lưu trữ dữ liệu chính tắc
  • Sử dụng lọc phía truy vấn (ví dụ: dạng xem) để đảm bảo rằng dữ liệu được truy xuất từ ​​cơ sở dữ liệu luôn ở trạng thái chính xác, ngay cả khi dữ liệu ở trạng thái nghỉ không

Một cách để vượt qua tất cả các vấn đề này là chèn một lớp API mà bạn kiểm soát giữa các chương trình có vấn đề ghi và cơ sở dữ liệu thực tế.

Có vẻ như một phần của vấn đề của bạn là bạn thậm chí không biết tất cả các địa điểm đang tạo ra ghi sai - hoặc đơn giản là có quá nhiều trong số chúng để bạn cập nhật. Đó là một trạng thái đáng sợ để tồn tại, nhưng nó không bao giờ nên được phép phát sinh ở nơi đầu tiên.

Ngay khi bạn nhận được nhiều hơn một số hệ thống được phép sửa đổi dữ liệu trong kho lưu trữ dữ liệu sản xuất chính tắc, bạn sẽ gặp rắc rối: không có cách nào để duy trì tập trung bất cứ điều gì về cơ sở dữ liệu đó. Tốt hơn là nên cho phép càng ít quá trình phát hành ghi và sử dụng chúng như là "người gác cổng" có thể xử lý trước dữ liệu trước khi chèn khi cần thiết. Cơ chế chính xác cho điều này thực sự phụ thuộc vào kiến ​​trúc cụ thể của bạn.


"Nếu bạn có các chương trình chèn dữ liệu không chính xác vào cơ sở dữ liệu của mình, các chương trình đó đã bị hỏng và cần được sửa chữa." đó cũng là lý thuyết tuyệt vời, nhưng thực tế là họ vẫn sẽ thêm hồ sơ trong khi một số ủy ban tiếp tục tranh luận về việc nên sử dụng "NA" hay "Không".
JeffO

@JeffO: Không có ủy ban nào nên tranh luận về việc có nên lưu trữ "NA", "Không", NULL hay thứ gì khác trong cơ sở dữ liệu hay không. Các bên liên quan phi kỹ thuật có cổ phần trong những gì dữ liệu đến hiện của cơ sở dữ liệu và làm thế nào nó được sử dụng, nhưng không phải trong các đại diện bên trong.
Daniel Pryden

@DanielPryden: Ở công việc cuối cùng của tôi, chúng tôi đã có một Hội đồng Đánh giá Kiến trúc (với một tiểu ban DBA) sẽ xem xét các thay đổi kỹ thuật giữa các miền. Rất kỹ thuật, nhưng họ chỉ gặp nhau hai tuần một lần và nếu bạn không cung cấp đủ chi tiết cho họ thì họ sẽ trì hoãn quyết định cho đến khi bạn làm ... tại một cuộc họp tiếp theo. Hầu hết các thay đổi hệ thống không tầm thường không bao gồm thêm chức năng thông qua mã mới sẽ thường mất khoảng một tháng.
TMN

@DanielPryden - Tôi đã ngồi trong các cuộc họp với cuộc tranh luận của quản lý cấp trên về nhãn hộp văn bản. Bạn có thể lập luận rằng điều này không liên quan gì đến những gì bạn sẽ đặt tên cho nó trong ứng dụng hoặc cơ sở dữ liệu, nhưng thực tế là vậy.
JeffO

Đáp lại những bình luận về việc nhận được sự chấp thuận bổ sung cho những thay đổi của loại này: quan điểm của tôi về các giá trị là "không chính xác" giả định rằng các giá trị cho phép đã được ghi nhận ở đâu đó - đó là lý do tại sao OP nói rằng các giá trị này nên được coi là một lỗi. Nếu lược đồ của cơ sở dữ liệu được chỉ định để cho phép một giá trị, thì giá trị đó không phải là một lỗi. Vấn đề là nếu bạn có dữ liệu không khớp với lược đồ của mình thì sẽ bị hỏng: ưu tiên của bạn là làm cho dữ liệu và lược đồ khớp với nhau. Tùy thuộc vào nhóm, điều đó có thể liên quan đến việc thay đổi dữ liệu, lược đồ hoặc cả hai.
Daniel Pryden

2

" Có bất kỳ nguyên tắc thiết kế hoặc kiến ​​trúc tốt nào để xử lý các mục null hiếm nhưng có thể không? "

Câu trả lời đơn giản - có.

ETL

Tiến hành một số xử lý trước để đảm bảo dữ liệu có chất lượng đủ để đi vào cơ sở dữ liệu. Bất cứ điều gì trong tệp thả phải được báo cáo lại và mọi dữ liệu sạch có thể được tải vào cơ sở dữ liệu.

Là một người vừa là kẻ săn trộm vừa là người quản lý trò chơi (DBA), tôi biết từ kinh nghiệm cay đắng rằng các bên thứ 3 đơn giản sẽ không giải quyết vấn đề dữ liệu của họ trừ khi họ bị ép buộc. Liên tục cúi xuống về phía sau và xoa bóp dữ liệu thông qua thiết lập một tiền lệ nguy hiểm.

Mart / Kho lưu trữ

Trong kịch bản này, dữ liệu thô được đẩy vào kho lưu trữ DB và sau đó phiên bản được khử trùng được đẩy đến mart DB mà ứng dụng sau đó có quyền truy cập.

Giá trị mặc định

Nếu bạn có thể áp dụng các giá trị mặc định hợp lý cho các cột thì bạn nên mặc dù điều này có thể liên quan đến một số công việc nếu đây là cơ sở dữ liệu hiện có.

Thất bại sớm

Thật là hấp dẫn khi chỉ cần giải quyết các vấn đề dữ liệu tại cổng vào ứng dụng, bộ báo cáo, giao diện, v.v ... Tôi khuyên bạn không nên chỉ dựa vào điều này. Nếu bạn kết nối một số tiện ích khác với DB, bạn sẽ có thể gặp lại vấn đề tương tự. Giải quyết các vấn đề chất lượng dữ liệu.


+1 Đây là những gì tôi sẽ làm, thu thập tất cả dữ liệu và tạo một bộ dữ liệu hợp lệ để ứng dụng của bạn xử lý.
Kwebble

1

Bất cứ khi nào trường hợp sử dụng của bạn cho phép thay thế NULL một cách an toàn bằng một giá trị mặc định tốt, bạn có thể thực hiện chuyển đổi trong các SELECTcâu lệnh Sql bằng cách sử dụng ISNULLhoặc COALESCE. Vì vậy, thay vì

 SELECT MyColumn FROM MyTable

người ta có thể viết

 SELECT ISNULL(MyColumn,DefaultValueForMyColumn) FROM MyTable

Tất nhiên, điều đó sẽ chỉ hoạt động khi ORM cho phép thao tác trực tiếp với các câu lệnh được chọn hoặc cung cấp các mẫu có thể thay đổi để tạo. Mọi người nên đảm bảo rằng không có lỗi "thực" nào được che dấu theo cách này, vì vậy chỉ áp dụng nếu thay thế bằng một giá trị mặc định là chính xác những gì bạn muốn trong trường hợp NULL.

Nếu bạn có thể thay đổi cơ sở dữ liệu và lược đồ và hệ thống db của bạn hỗ trợ điều này, bạn có thể xem xét để thêm một mệnh đề giá trị mặc định vào các cột cụ thể, như được đề xuất bởi @RobbieDee. Tuy nhiên, điều này cũng sẽ yêu cầu sửa đổi dữ liệu hiện có trong cơ sở dữ liệu để loại bỏ mọi giá trị NULL được chèn trước đó và nó sẽ loại bỏ khả năng phân biệt giữa dữ liệu nhập chính xác và không đầy đủ sau đó.

Từ kinh nghiệm của bản thân, tôi biết rằng việc sử dụng ISNULL có thể hoạt động tốt một cách đáng ngạc nhiên - trước đây tôi phải duy trì một ứng dụng cũ mà các nhà phát triển ban đầu đã quên thêm các ràng buộc KHÔNG NULL vào nhiều cột và chúng tôi không thể dễ dàng thêm các ràng buộc đó sau đối với một số lý do. Nhưng trong 99% của tất cả các trường hợp, 0 làm mặc định cho các cột số và chuỗi trống làm mặc định cho các cột văn bản là hoàn toàn chấp nhận được.


Trong khi điều này hoạt động, cuối cùng bạn có thể phải sao chép mã phòng thủ cho mỗi CHỌN. Cách tiếp cận tốt hơn nhiều là xác định giá trị mặc định cho cột khi chèn NULL mặc dù điều này có thể không khả thi / mong muốn vì nhiều lý do.
Robbie Dee

@RobbieDee: cảm ơn vì nhận xét đó, tôi đã thay đổi câu trả lời của mình cho phù hợp. Tuy nhiên, nếu điều này là "tốt hơn nhiều" là tranh cãi. Khi mã CRUD ở một nơi, mã phòng thủ trùng lặp có thể không thành vấn đề. Và nếu không, đã có một số sao chép mã trước đó.
Doc Brown

Hoạt động CRUD đơn giản tất nhiên là lý tưởng. Nhưng trong thế giới thực, các hệ thống thường có chế độ xem UI phức tạp, trình hướng dẫn dữ liệu do người dùng tạo, báo cáo, v.v. Nhưng như bạn đã chỉ ra, các giá trị mặc định cần phải có từ đầu hoặc ít nhất là cần một số nỗ lực chuyển đổi ban đầu. Những gì bạn đã mô tả có thể thích hợp hơn trong phát triển trường nâu.
Robbie Dee

Câu trả lời hay nhất. Các ứng dụng mới thường thêm một số dữ liệu mới có thể nằm ngoài tầm kiểm soát của bạn. Các NULL sai lầm thường đến từ việc nhập dữ liệu cũ vào cơ sở dữ liệu được thiết kế lại. Các ràng buộc được tắt cho điều này để cho phép nó hoàn thành trong một vài giờ thay vì vài ngày. "Thất bại lớn" thường xuất hiện khi các DBA cố gắng kích hoạt lại các ràng buộc. Vì nó không bao giờ được lên kế hoạch, quản lý thường chùn bước trong những tuần làm việc thường được yêu cầu để sửa dữ liệu xấu, vì vậy nó vẫn còn. Tất cả các ứng dụng nên xử lý duyên dáng các NULL bằng cách chèn mặc định và báo cáo hoặc nhắc nhở về dữ liệu bị thiếu.
DocSalvager

1

OP đang đưa ra một câu trả lời rằng các cặp vợ chồng quy tắc kinh doanh với các chi tiết kỹ thuật cơ sở dữ liệu.

Điều này "về mặt lý thuyết" sẽ không xảy ra, vì vậy nếu nó chỉ ra dữ liệu xấu hoặc lỗi trong mã. Các lỗi có mức độ nghiêm trọng khác nhau, tùy thuộc vào lĩnh vực nào là null; tức là đối với một số trường, quá trình xử lý phải được dừng lại và ai đó đã thông báo, đối với những trường khác, việc xử lý sẽ được phép tiếp tục và chỉ cần thông báo cho ai đó.

Đây là tất cả các quy tắc kinh doanh. Các quy tắc kinh doanh không quan tâm đến null per-se. Đối với tất cả những gì nó biết cơ sở dữ liệu có thể có null, 9999, "BOO!" ... Nó chỉ là một giá trị khác. Điều đó, trong RDBMS, null có các thuộc tính thú vị và cách sử dụng duy nhất là moot.

Điều duy nhất quan trọng là "null-ness" nghĩa là gì đối với (các) đối tượng kinh doanh nhất định ...

Có bất kỳ nguyên tắc kiến ​​trúc hoặc thiết kế tốt để xử lý các mục null hiếm nhưng có thể không?

Đúng.

  • Đặt quy tắc kinh doanh trong các lớp học.
  • Việc chuyển ngữ phải ở trong một lớp mã thích hợp tách rời các lớp nghiệp vụ và lưu trữ dữ liệu. Nếu bạn không thể đặt nó vào mã ORM thì ít nhất đừng đặt nó vào cơ sở dữ liệu.
  • Làm cho cơ sở dữ liệu câm nhất có thể, không có quy tắc kinh doanh ở đây. Ngay cả những thứ vô thưởng vô phạt như mặc định một giá trị sẽ cắn bạn . Đã ở đó.
  • Xác thực dữ liệu đi và đến từ cơ sở dữ liệu. Và tất nhiên điều này được thực hiện trong bối cảnh của các đối tượng kinh doanh.

Ném một ngoại lệ khi truy xuất dữ liệu không có ý nghĩa.

Câu hỏi là "tôi có nên lưu trữ dữ liệu" xấu "không? Nó phụ thuộc:

  • Dữ liệu xấu có thể được sử dụng - Không bao giờ lưu các đối tượng không hợp lệ hoặc vật liệu tổng hợp đối tượng. Dữ liệu phức tạp / mối quan hệ kinh doanh ở khắp mọi nơi. Người dùng có thể thực hiện bất kỳ chức năng nào tại bất kỳ thời điểm nào, có thể sử dụng thực thể kinh doanh đó trong một số bối cảnh. Hiệu ứng (nếu có) của dữ liệu xấu, tại thời điểm nó được lưu, không được biết vì nó phụ thuộc nhiều vào việc sử dụng trong tương lai. Không có quy trình thống nhất / duy nhất của dữ liệu đó.
  • Không thể tiến triển nếu có dữ liệu xấu - Cho phép lưu dữ liệu xấu. Tuy nhiên, bước tiếp theo trong một quy trình không thể tiếp tục cho đến khi mọi thứ hợp lệ. Ví dụ: làm thuế thu nhập của một người. Khi được truy xuất từ ​​cơ sở dữ liệu, phần mềm chỉ ra các lỗi và nó không thể được gửi tới IRS mà không cần kiểm tra tính hợp lệ.

0

Có nhiều cách để xử lý null, vì vậy chúng tôi sẽ chuyển từ lớp cơ sở dữ liệu lên lớp ứng dụng.


Lớp cơ sở dữ liệu

Bạn có thể cấm null ; mặc dù ở đây nó không thực tế

Bạn có thể định cấu hình mặc định trên cơ sở mỗi cột:

  • nó yêu cầu cột không có trong đó insert, vì vậy không bao gồm chèn null rõ ràng
  • nó ngăn chặn sự phát hiện từ các hàng mà insertcột này bị bỏ sót

Bạn có thể định cấu hình trình kích hoạt để khi chèn các giá trị bị thiếu sẽ tự động được tính toán:

  • nó đòi hỏi phải có thông tin cần thiết để thực hiện tính toán này
  • nó sẽ làm chậm insert

Lớp truy vấn

Bạn có thể bỏ qua các hàng có sự bất tiện null:

  • nó đơn giản hóa logic chính
  • nó ngăn chặn việc phát hiện các "hàng xấu", vì vậy cần có một quy trình khác để kiểm tra chúng
  • nó đòi hỏi mỗi truy vấn phải được ghi lại

Bạn có thể cung cấp một giá trị mặc định trong truy vấn:

  • nó đơn giản hóa logic chính
  • nó ngăn chặn việc phát hiện các "hàng xấu", vì vậy cần có một quy trình khác để kiểm tra chúng
  • nó đòi hỏi mỗi truy vấn phải được ghi lại

Lưu ý: thiết bị cho mỗi truy vấn không nhất thiết là một vấn đề nếu bạn có một số cách tự động tạo chúng.


Lớp ứng dụng

Bạn có thể kiểm tra trước bảng cấm null:

  • nó đơn giản hóa logic chính
  • nó cải thiện thời gian để thất bại
  • nó đòi hỏi phải giữ sự kiểm tra trước và logic ứng dụng nhất quán

Bạn có thể làm gián đoạn quá trình xử lý khi gặp lệnh cấm null:

  • nó tránh trùng lặp kiến ​​thức về các cột có thể nullvà không thể
  • nó vẫn tương đối đơn giản (chỉ cần kiểm tra + trả lại / ném)
  • nó yêu cầu quá trình của bạn có thể được nối lại (nếu bạn đã gửi e-mail, không muốn gửi nó hai lần hoặc một trăm lần!)

Bạn có thể bỏ qua hàng khi gặp lệnh cấm null:

  • nó tránh trùng lặp kiến ​​thức về các cột có thể nullvà không thể
  • nó vẫn tương đối đơn giản (chỉ cần kiểm tra + trả lại / ném)
  • nó không yêu cầu quá trình của bạn được nối lại

Bạn có thể gửi thông báo khi gặp lệnh cấm null, mỗi lần một hoặc theo đợt, miễn phí theo các cách khác được trình bày ở trên. Tuy nhiên, vấn đề quan trọng nhất là "sau đó là gì?", Đáng chú ý nhất là nếu bạn mong muốn hàng được vá và cần được xử lý lại, bạn có thể cần đảm bảo rằng bạn có một số cách để phân biệt các hàng đã được xử lý với các hàng cần đang được xử lý lại.


Với tình huống của bạn, tôi sẽ xử lý tình huống tại ứng dụng và kết hợp:

  • làm gián đoạnthông báo
  • bỏ quathông báo

Tôi sẽ có xu hướng chỉ bỏ qua nếu có thể bằng cách nào đó đảm bảo một chút tiến bộ, đặc biệt là nếu việc xử lý có thể mất thời gian.

Nếu bạn không cần xử lý lại các hàng bị bỏ qua, thì chỉ cần đăng nhập chúng là đủ và một e-mail được gửi ở cuối quá trình với số lượng hàng bị bỏ qua sẽ là một thông báo thích hợp.

Mặt khác, tôi sẽ sử dụng bảng phụ cho các hàng được cố định (và được xử lý lại). Bảng phụ này có thể là một tài liệu tham khảo đơn giản (không có khóa ngoại) hoặc bản sao đầy đủ: cái sau, ngay cả khi đắt hơn, là cần thiết nếu bạn không có thời gian để giải quyết nulltrước khi phải dọn sạch dữ liệu chính.


-1

Nulls có thể được xử lý trong việc dịch hoặc ánh xạ các loại cơ sở dữ liệu sang các loại ngôn ngữ. Ví dụ: trong C #, đây là một phương thức chung xử lý null cho bạn cho bất kỳ loại nào:

public static T Convert<T>(object obj)
        {
            if (obj == DBNull.Value)
            {
                return default(T);
            }

            return (T) obj;
        }

public static T Convert<T>(object obj, T defaultValue)
        {
            if (obj == DBNull.Value)
            {
                T t = defaultValue;
                return t;
            }

            return (T) obj;
        }

Hoặc, nếu bạn muốn thực hiện hành động ...

 public static T Convert<T>(object obj, T defaultValue)
        {
            if (obj == DBNull.Value)
            {
                //Send an Alert, we might want pass in the name
                //of column or other details as well
                SendNullAlert();
                //Set it to default so we can keep processing
                T t = defaultValue;
                return t;
            }

            return (T) obj;
        }

Và sau đó, trong ánh xạ, trong trường hợp này là một đối tượng thuộc loại "Mẫu", chúng tôi sẽ xử lý null cho bất kỳ cột nào:

public class SampleMapper : MapperBase<Sample>
    {
        private const string Id = "Id";
        private const string Name = "Name";
        private const string DataValue = "DataValue";
        private const string Created = "Created";

        protected override Sample Map(IDataRecord record)
        {
            return new Sample(
                Utility.Convert<Int64>(record[Id]),
                Utility.Convert<String>(record[Name]),
                Utility.Convert<Int32>(record[DataValue]),
                Utility.Convert<DateTime>(record[Created])
                );
        }
    }

Cuối cùng, tất cả các lớp ánh xạ có thể được tạo tự động dựa trên truy vấn SQL hoặc các bảng có liên quan bằng cách xem các kiểu dữ liệu SQL và dịch chúng sang các kiểu dữ liệu cụ thể của ngôn ngữ. Đây là những gì nhiều ORM làm cho bạn tự động. Lưu ý rằng một số loại cơ sở dữ liệu có thể không có ánh xạ trực tiếp (colunms không gian địa lý, v.v.) và có thể cần xử lý đặc biệt.


Nếu ai đó muốn đăng phiên bản Java tương đương sẽ rất tuyệt ...
Jon Raynor

Tôi nghĩ rằng mã ví dụ là hoàn toàn dễ hiểu đối với các nhà phát triển Java. Trong tình huống của tôi, tôi đã có sẵn một ORM, vì vậy không cần phải thực hiện. Nhưng câu trả lời của bạn chỉ giải quyết các giá trị mặc định cho null, trong khi đó trong trường hợp của tôi, thực tế trường hợp quan trọng hơn nhiều là phát hiện null và kích hoạt một hành động (ví dụ: thông báo cho quản trị viên về dữ liệu sai sót).
jhyot

Ahhh, tôi sẽ cập nhật câu trả lời của tôi dựa trên điều này.
Jon Raynor

Mã đã chỉnh sửa của bạn hiện có một hành động mặc định cho bất kỳ giá trị null nào (nghĩa là nó hoàn toàn chung chung). Điều đó rất giống với lựa chọn thứ 2 của tôi trong câu hỏi ban đầu, tức là chỉ cần ném vào null và bắt nó ở đâu đó. Nhưng như đã nêu ở đó, tôi cần phân biệt các hành động dựa trên giá trị nào bị thiếu.
jhyot
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.