7

Mój projekt używa hibernacji z menedżerem transakcji wiosennych, a moja baza danych to postgres (może być nieistotna).Obsługa ograniczenia bazy danych hibernacji

Próbuję odczytać duże pliki xml i skonstruować obiekty z nich (obiekty nie są duże, ale ilość jest) i wstawić je do bazy danych.

Jeśli przez przypadek jeden z moich obiektów narusza ograniczenia bazy danych, cały proces zatrzymuje się. Jak mogę pominąć te, które naruszają ograniczenia bazy danych? ewentualnie zalogować ich identyfikator lub cokolwiek do pliku dziennika?

aktualizacja Pytanie:

Byłem przeglądania koryta SO i okazało się, że dla wkładek wsadowych najlepiej zaleca się stosowanie sesji Stateless ale wciąż ten sam problem i wstawić zatrzymuje:

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. 

Oto odpowiednie części mojego kodu do parsowania xml i wstawiania do db, dla uproszczenia załóżmy, że wstawiam filmy:

//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); 
    } 
} 

Mam tę właściwość ustawioną w app-ctx hibernate.jdbc.batch_size na 100. Czy naprawdę należy wybrać przed wstawieniem, aby tego uniknąć?

Aktualizacja 2:

Jeśli używam StatelessSession zamiast sesji, mam arround 20 wkładki i od przystanków przetwarzania czas nieokreślony bez wyjątku czy cokolwiek.

Zakładam, że numer 20 jest, ponieważ łączę połączenia z tomcat i mam maxActive="20".

Bounty Aktualizacja:

Chciałbym naprawdę kochać, aby zobaczyć rozwiązanie ktoś oferta (bez obronny wybierz jeśli to możliwe). Używanie statelessSession lub po prostu sesja.

Odpowiedz

4

Większość rodzajów ograniczeń, na przykład jeśli kolumna ma wartość pustą lub ma maksymalną szerokość, można sprawdzić, używając Hibernate Validator. Po prostu ręcznie wykonaj sprawdzanie poprawności na obiekcie przed próbą utrzymania go.

W przypadku niektórych rzeczy, w szczególności unikalnych ograniczeń, należy albo wybrać opcję "defensywną", aby sprawdzić, czy kolizja istnieje, albo zachować zestaw wartości już wprowadzonych do pamięci.

2

Aby wstawić dużą liczbę obiektów z pliku xml, należy rozważyć użycie partii sprężyny. Parametr skip-limit pozwala określić liczbę błędnych linii w pliku xml przed zatrzymaniem procesu wsadowego. Sprawdź także pomiń-policy i skippable-exception; seee Configuring a Step w dokumentacji Spring.

Jeśli nie chcesz używać partii sprężystej, po prostu skorzystaj z prostego sprawdzenia, które pozwoli ci kontynuować proces do końca.

+0

Prosta instrukcja try catch nie zrobi. Po wystąpieniu wyjątku przez Hibernate, stan sesji jest niespójny, transakcja musi zostać wycofana, a sesja zamknięta. Co więcej, wyjątek zostanie rzucony tylko w czasie spłukiwania, długo po tym, jak utrwalono wadliwy zapis. –

+0

Dlatego zaleca się stosowanie bezstanowej sesji hibernacji w takich przypadkach. Zapobiegnie to niespójnemu stanowi, a także zmniejszy zużycie pamięci (lub nie będziesz musiał eksmitować już leczonych podmiotów) –

1

Myślę, że Affe ma właściwe podejście z defensywnym wyborem przed wstawieniem.

Możesz rozważyć użycie savepoint przed każdą wstawką i wycofanie do punktu zapisu, jeśli zostanie zgłoszony wyjątek. Narzut na wydajność związany z tworzeniem punktu zapisu. Punkt oszczędzania będzie musiał zostać zwolniony, kiedy skończysz.

Zobacz AbstractTransactionStatus.setSavepoint() lub jeśli masz dostęp do puli połączeń JDBC setSavepointrollback(Savepoint) i releaseSavepoint(Savepoint)

2

Jak myślisz, dlaczego to wszystko musi być jedna duża transakcja? Wszystko, co opisujesz, sugeruje mi, że w rzeczywistości masz tu wiele transakcji. W przypadku obiektów, które "pomijają", po prostu usuń tę encję i wycofaj transakcję. Staje się nieco bardziej złożony, jeśli element "FILM" definiuje wykres obiektów, ale idea jest taka sama.

4

Myślę, że niemożliwe jest zatwierdzenie czegoś tak kompletnie, że można zagwarantować pomyślne wstawienie. W niektórych przypadkach, niezależnie od tego, co robisz, ktoś inny może wstawić coś do bazy danych między sprawdzaniem poprawności i wstawić, powodując naruszenie ograniczeń.

W większości przypadków po prostu polecam obsłużyć wyjątek, jak każdy inny.

0

Chociaż to stare pytanie, ostatnio stanąłem w podobnej sytuacji i oto co zrobiłem.

Użyłem też sesji bezpaństwowych, ale oto co zrobiłem inaczej. Wystąpiłem session.insert, który albo się kończy, albo się nie powiedzie z powodu naruszenia ograniczeń, w górę na naruszenie ograniczeń Wywołany wyjątek ConstraintViolationException, wychwytując obiekt, który zawiodł wstawił, rób to, co kiedykolwiek chciałeś zrobić z nieudanym obiektem. Wraz z transakcjami używane są również punkty zapisu dla każdej wkładki (punkty zapisu są tańsze i nie powodują tak dużego wpływu na wydajność), więc gdy transakcja nie powiedzie się z powodu jakiegoś problemu, zatwierdzenie jest wykonywane do ostatniego punktu zapisu (w klauzuli catch).

mój kod wyglądał mniej więcej tak:

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