2008-10-03 8 views
8

Đây là phiên bản cụ thể của this question.
Tôi muốn kiểm tra xem tôi có đang chèn hàng trùng lặp hay không. Tôi có nên kiểm tra nó theo chương trình trong lớp ứng dụng của mình không:Logic: Cơ sở dữ liệu hoặc Ứng dụng/2 (kiểm tra ràng buộc)

if (exists(obj)) 
{ 
    throw new DuplicateObjectException(); 
} 
HibernateSessionFactory.getSession().save(obj); 

hoặc tôi nên bắt ngoại lệ được ném bởi lớp cơ sở dữ liệu và được kích hoạt khi tôi vi phạm các giới hạn?

try 
{ 
    HibernateSessionFactory.getSession().save(obj); 
} 
catch(ConstraintViolationException e) 
{ 
    throw new DuplicateObjectException(); 
} 

EDIT: Nói cách khác: dù khó khăn là có để duy trì (đó là thiết kế cơ sở dữ liệu tốt dù sao, và tôi không thể chắc chắn ứng dụng của tôi sẽ là người duy nhất truy cập vào bảng) tôi sẽ dựa về ràng buộc và xử lý ngoại lệ, vi phạm của nó sẽ tăng lên, hoặc tôi sẽ kiểm tra tốt hơn?

EDIT2: Dĩ nhiên tôi kiểm tra + chèn trong một giao dịch, khóa bảng để đảm bảo không có quá trình khác đang viết kỷ lục khác trong khi chờ đợi

Trả lời

7

Trước tiên, bạn phải có khóa chính hoặc ràng buộc duy nhất trên cơ sở dữ liệu để thực thi tính độc đáo này - không có câu hỏi.

Cho rằng ràng buộc tồn tại, bạn nên viết mã nào trong ứng dụng? Sở thích của tôi là thử chèn và bắt các ngoại lệ. Bởi vì có lẽ hầu hết các chèn sẽ thành công, chỉ một số ít sẽ thất bại như các bản sao (đó là những gì "ngoại lệ" ngụ ý!): Nó không hiệu quả để thực hiện kiểm tra tồn tại trước mỗi lần chèn, khi cơ sở dữ liệu sẽ thực hiện kiểm tra ràng buộc của chính nó.

Ngoài ra, về mặt lý thuyết có thể cho phép kiểm tra tồn tại là sai - nếu người khác quản lý bản ghi có cùng giá trị khóa trong khoảng thời gian nhỏ giữa séc hiện tại và khoản chèn của bạn. Sau đó, nếu bạn không bẫy ngoại lệ cơ sở dữ liệu, bạn sẽ tin rằng chèn đã thành công khi trên thực tế nó không.

1

Nói chung, tôi cố gắng tránh mã hóa dựa trên lỗi bị ném vì tôi đã làm điều gì sai. Đôi khi, mặc dù, đó là tất cả những gì bạn có thể làm. Trong tình huống của bạn, tôi nghĩ bạn nên kiểm tra trước.

2

Bạn cần nắm bắt ngoại lệ cơ sở dữ liệu trừ khi bạn có thể đảm bảo rằng ứng dụng của bạn là ứng dụng duy nhất bao giờ chèn hàng (và sẽ chèn hàng) vào cơ sở dữ liệu của bạn.

EDIT: Tôi có thể hiểu sai câu hỏi, nhưng tôi vẫn cho rằng tùy chọn B (HibernateSessionFactory ném ConstraintException từ cơ sở dữ liệu) là tùy chọn tốt hơn. Luôn luôn có một cơ hội nhỏ mà một ứng dụng khác có thể chèn một cái gì đó trong phần thời gian giữa séc của bạn và cuộc gọi chức năng thực tế. Ngoài ra, cách duy nhất để kiểm tra một bản dupe là thực hiện một truy vấn bổ sung mà chỉ là một cống không cần thiết về hiệu suất.

Sự hiểu biết ban đầu của tôi về câu hỏi là trong tùy chọn A kiểm tra dupe sẽ được thực hiện trong nội bộ (tức là chỉ sử dụng cấu trúc dữ liệu mà chương trình đã tạo và không có truy vấn cho đến INSERT). Câu trả lời ban đầu của tôi là để đáp ứng với phương pháp này.

1

Điều này sẽ phá vỡ (cho phép các mục nhập trùng lặp) nếu ràng buộc bị giảm vì một lý do nào đó (thường là công việc bảo trì mà DBA bỏ qua để kích hoạt lại nó). Bạn nên kiểm tra tình huống này trong ứng dụng.

Tuy nhiên, đó là thiết kế cơ sở dữ liệu tốt để có cơ sở dữ liệu thực thi ràng buộc (như bạn đã hoàn toàn đúng) vì những người khác cũng có thể đang sử dụng cơ sở dữ liệu. Như một khái quát hóa, tốt nhất là giả sử rằng các ứng dụng và cơ sở dữ liệu sống trong một mối quan hệ M: M - đây sẽ là trường hợp gần như mọi lúc.

1

Các trường hợp ngoại lệ được Hibernate ném (hoặc bất kỳ thành phần ORM nào) có xu hướng khó giải thích.

Nếu ngoại lệ có đủ thông tin mà bạn có thể tạo thông báo lỗi thực sự giúp người dùng, thì chỉ cần nắm bắt ngoại lệ, phân tích và tiếp tục.

Nếu ngoại lệ không có đủ thông tin, bạn phải kiểm tra điều kiện lỗi và tạo thông báo lỗi hữu ích cho người dùng rằng họ đang làm điều gì đó sai.

Câu hỏi là một trong những "ngoại lệ mờ đục" như thế nào? Một số khá mờ. Những người khác có đủ để bạn có thể phân tích cú pháp chuỗi tin nhắn và tìm ra điều cần nói với người dùng.

0

Khi hibernate ném ngoại lệ từ phiên bạn must discard the session (xem phần 11.2.3). Vì vậy, nếu bạn cần phải kiểm tra cho dups và tiếp tục sử dụng cùng một phiên sau đó bạn không có sự lựa chọn, nhưng để kiểm tra đầu tiên trong ứng dụng. Ngoài ra có khả năng với mã trong đoạn 1 mà một quá trình khác có thể chèn một bản ghi có thể khiến cho ngoại lệ trùng lặp được ném giữa thời gian bạn kiểm tra bản ghi trùng lặp và thời gian nó được chèn vào thực tế.

2

Bạn kiểm tra xem đối tượng có tồn tại duy nhất trong mã ứng dụng không, và sau đó một khi đã hài lòng rằng nó không, tiết kiệm một cách phù hợp đối tượng. Nhưng một khách hàng đồng thời khác có thể chèn đối tượng của riêng họ vào lúc giữa hai dòng mã của bạn. Vì vậy, bạn sẽ nhận được một ngoại lệ trùng lặp anyway, chỉ có thời gian này bạn không bắt nó.

Bạn phải thực hiện lưu() và bắt ngoại lệ. Nếu không, bạn có một điều kiện chủng tộc với các khách hàng đồng thời khác làm việc trên cùng một cơ sở dữ liệu.