7

Dự án của tôi đang sử dụng ngủ đông với trình quản lý giao dịch mùa xuân và cơ sở dữ liệu của tôi là postgres (có thể không liên quan).xử lý hạn chế cơ sở dữ liệu hibernate

Tôi đang cố gắng đọc các tệp xml lớn và xây dựng các đối tượng ra khỏi các tệp đó (các đối tượng không lớn nhưng số lượng là) và chèn chúng vào cơ sở dữ liệu.

Nếu một số cơ hội của một trong các đối tượng của tôi vi phạm ràng buộc cơ sở dữ liệu thì toàn bộ quá trình sẽ dừng. Làm thế nào tôi có thể bỏ qua những cái vi phạm ràng buộc cơ sở dữ liệu? cách khác đăng nhập id của họ hoặc bất cứ điều gì để một tập tin đăng nhập?

Câu hỏi cập nhật:

Tôi đã xem máng SO và thấy rằng cho chèn hàng loạt nó tốt nhất nên sử dụng phiên Stateless nhưng tôi vẫn nhận được cùng một vấn đề và chèn dừng:

May 26, 2012 4:45:47 PM org.hibernate.util.JDBCExceptionReporter logExceptions 
SEVERE: ERROR: duplicate key value violates unique constraint "UN_FK" 
    Detail: Key (fid)=(H1) already exists. 

Dưới đây là các phần liên quan của mã của tôi để phân tích cú pháp xml và chèn vào db, để đơn giản giả sử tôi đang chèn phim:

//class field 
@Autowired 
private SessionFactory sessionFactory; 

@Override 
public void startDocument() throws SAXException { 
    session = sessionFactory.getCurrentSession(); 
} 

@Override 
public void endElement(String uri, String localName, String qName) throws SAXException { 
if (qName.equalsIgnoreCase("FILM")) { 
     movie.setCategory(category); 
     movie.setAdded(new Date()); 
     session.insert(movie); 
    } 
} 

Tôi và có thuộc tính này được đặt trong ứng dụng-ctx hibernate.jdbc.batch_size đến 100. Có thực sự cần thiết phải chọn trước khi chèn để tránh điều này không?

Cập nhật 2:

Nếu tôi sử dụng StatelessSession thay phiên, tôi nhận được arround 20 chèn và so với điểm dừng xử lý vô thời hạn mà không cần bất kỳ ngoại lệ hoặc bất cứ điều gì.

Tôi giả định số 20 là vì tôi đang gộp các kết nối với tomcat và có maxActive="20".

Bounty Cập nhật:

tôi thực sự thích nhìn thấy giải pháp có người phục vụ (không có phòng thủ chọn nếu có thể). Sử dụng statelessSession hoặc chỉ phiên.

Trả lời

4

Hầu hết các loại ràng buộc, chẳng hạn như nếu cột có thể rỗng hoặc có chiều rộng tối đa, bạn có thể kiểm tra bằng cách sử dụng Hibernate Validator. Chỉ cần thực hiện thủ công việc xác thực trên đối tượng trước khi cố gắng duy trì nó. Đối với một số vấn đề, đặc biệt là các ràng buộc duy nhất, bạn cần phải thực hiện lựa chọn 'phòng thủ' để xem có va chạm hay không, hoặc duy trì bộ nhớ của các giá trị đã được chèn vào.

2

Để chèn một lượng lớn đối tượng từ tệp xml, bạn nên cân nhắc sử dụng lô mùa xuân. Giới hạn bỏ qua tham số cho phép bạn cho biết có bao nhiêu dòng sai lệch mà bạn có thể có trong xml của mình trước khi dừng quá trình xử lý hàng loạt. Kiểm tra cũng bỏ qua chính sách và ngoại lệ có thể bỏ qua; seee Configuring a Step trong tài liệu Spring.

Nếu bạn không muốn sử dụng lô mùa xuân, chỉ cần sử dụng một lần thử đơn giản sẽ cho phép quá trình của bạn tiếp tục cho đến khi kết thúc.

+0

Một câu lệnh try catch đơn giản sẽ không làm. Một khi ngoại lệ được ném bởi Hibernate, trạng thái phiên là không mạch lạc, giao dịch phải được khôi phục và phiên đã đóng. Hơn nữa, ngoại lệ sẽ chỉ được ném vào thời gian xả, lâu sau khi bản ghi bị lỗi đã được duy trì. –

+0

Đây là lý do tại sao nó được khuyến khích sử dụng một phiên Hibernate không trạng thái cho các trường hợp như vậy. Nó sẽ ngăn chặn trạng thái không mạch lạc và cũng làm giảm mức tiêu thụ bộ nhớ (hoặc bạn sẽ không phải loại bỏ các thực thể đã được xử lý) –

1

Tôi nghĩ rằng Affe có phương pháp phù hợp với lựa chọn phòng thủ trước khi chèn.

Bạn có thể xem xét sử dụng savepoint trước mỗi lần chèn và quay lại điểm lưu trữ nếu một ngoại lệ được ném. Sẽ có một chi phí hiệu suất của việc tạo một điểm lưu trữ. Điểm lưu trữ sẽ cần được giải phóng khi bạn hoàn thành.

Xem AbstractTransactionStatus.setSavepoint() hoặc nếu bạn có quyền truy cập vào các hồ bơi kết nối JDBC setSavepointrollback(Savepoint)releaseSavepoint(Savepoint)

2

Tại sao bạn nghĩ rằng đây tất cả đã trở thành một giao dịch lớn? Tất cả mọi thứ bạn mô tả trong thực tế ngụ ý với tôi rằng bạn trong thực tế có rất nhiều giao dịch ở đây. Đối với các đối tượng "lỗi", chỉ cần loại bỏ thực thể đó và khôi phục giao dịch. Nó phức tạp hơn một chút nếu phần tử "FILM" định nghĩa một đồ thị của các đối tượng, nhưng ý tưởng là như nhau.

4

Tôi nghĩ rằng không thể xác thực điều gì đó hoàn toàn đến nỗi bạn có thể đảm bảo chèn thành công. Trong một số trường hợp, không có vấn đề gì bạn làm, một người nào khác có thể chèn một cái gì đó vào DB giữa xác nhận và chèn gây ra một sự vi phạm ràng buộc.

Trong hầu hết các trường hợp, tôi chỉ khuyên bạn xử lý ngoại lệ như bất kỳ trường hợp nào khác.

0

Mặc dù đó là một câu hỏi cũ, tôi đã đối mặt với một tình huống tương tự gần đây và đây là những gì tôi đã làm.

Tôi đã sử dụng các phiên không trạng thái quá nhưng dưới đây là những gì tôi đã làm khác đi. Tôi đã phát hành session.insert thành công hoặc không thành công do vi phạm Constraint, lên Constraint vi phạm một ConstraintViolationException được ném, bắt nó sẽ cung cấp cho u đối tượng không chèn được, làm những gì bạn muốn làm với đối tượng thất bại. Cùng với các giao dịch cũng sử dụng lưu điểm cho mỗi lần chèn (tiết kiệm điểm rẻ hơn và không gây ra tác động hiệu suất lớn), vì vậy khi một giao dịch thất bại do một số vấn đề, cam kết được thực hiện cho đến lần lưu cuối cùng (trong điều khoản bắt).

mã của tôi trông như thế này:

try { 
    session.connection().setSavePoint("lastSaved"); 
    session.insert(obj); 
} 
catch(ConstraintViolationException) { 
    log.error(obj.getUserId()); 
    .... 
} 
tx.commit(); 
.... 
catch(TransactionException e) { 
    tx.rollback(); 
}