2014-05-20 10 views
5

Mam blok kodu, który aktualizuje rekordy w bazie danych. Zmniejszone przykład:Czy mogę ponownie użyć PreparedStatement, jeśli wystąpi wyjątek przejściowy?

... 
statement = connection.prepareStatement(
    "INSERT INTO thistable (name) VALUES (?)", 
    PreparedStatement.RETURN_GENERATED_KEYS 
); 
statement.setString(1, "Fred"); 
statement.addBatch(); 
statement.setString(2, "Joe"); 
statement.addBatch(); 
statement.executeBatch(); 
... 

Jest to część jakiegoś kodu, który przetwarza dużo zapisów, a kod działa wiele wątków do prędkości. Wszystko jest w porządku, ale gdy obciążenie wzrasta w środowisku na żywo, zauważyłem, że kilka rzutujących jest SQLTransientException s. Wygląda na to, że nie mogę nic z tym zrobić, z wyjątkiem ponownej próby transakcji.

Moje pytanie brzmi: czy partia mogła zostać wyczyszczona, nawet jeśli instrukcja nie powiodła się? Czy mogę po prostu powtórzyć linię executeBatch, czy muszę ponownie utworzyć całą partię? Czy jest to to samo w przypadku oświadczeń innych niż wsadowe?

Krótko mówiąc, czy jest to dobry sposób na obsługę wyjątków przejściowych?

statement.setString(1, "Fred"); 
statement.addBatch(); 
statement.setString(2, "Joe"); 
statement.addBatch(); 
for(int attempt = 0; ; attempt ++) { 
    try { 
     statement.executeBatch(); 
     break; 
    } catch(SQLTransientException ex) { 
     if(attempt >= 3) { 
      throw ex; 
     } 
     try { 
      Thread.sleep(attempt * attempt * 100); 
     } catch(InterruptedException ex2) { 
      throw ex; 
     } 
    } 
} 
+0

Oznaczyłem to pytanie MySQL, ponieważ właśnie tego używamy, ale staram się zrozumieć standardowe zachowanie, a nie zachowanie zależne od implementacji, ponieważ wkrótce przeprowadzamy migrację do PostgreSQL. – Dave

+0

Teoretycznie "SQLTransientException" powinno być zgłaszane tylko wtedy, gdy błąd pozwala na operacje, które mogą być ponawiane bez "bez interwencji przez funkcjonalność na poziomie aplikacji". –

+0

Czy masz jakieś państwo SQL dla tego wyjątku (getSQLState())? – Mani

Odpowiedz

2

Od API nie dostarcza najwięcej informacji na temat zachowania podczas SQLTransientException dzieje oprócz poniżej

when the driver has determined that the timeout value that was specified by the 
setQueryTimeout method has been exceeded and has at least attempted 
to cancel the currently running Statement 

zweryfikował Wdrożenie Mysql JDBC4.

W mojej obserwacji mogłem zobaczyć, że jest jeden możliwy SQLTimeoutException (tj. SQLTransientException) może się zdarzyć, jeśli upłynął limit czasu.

A gdy limit czasu, to nie jest po prostu czyszcząc ostatnie wypowiedzi, jest wyczyszczenie całej partii (przynajmniej w MySQL Realizacja)

// we timeout the entire batch, not individual statements 

tak, że część jest jasne.

I jak za JDBC Specyfikację

The statement’s batch is reset to empty once executeBatch returns 

Niezależnie od executeBatch rzuca wyjątek/uda byłoby wyczyścić partii.

Konkretnie Mysql Prepared Statement czyści partię na finaly bloku w executeBatch() metoda

finally { 
     this.statementExecuting.set(false); 
     clearBatch(); 
     } 

Więc logika nie będzie działać, ponieważ nie są dodawania sprawozdań do partii ponownie.

Dodaj wyciągi do partii i ponownie wykonaj. jest bardzo prawdopodobne, że ponownie skończysz w Timeout. Najpierw znajdź czas. jeśli to możliwe, napisz trochę informacji o przyczynie/stanie w dziennikach wykonania.

+0

Ręczne czyszczenie (na wszelki wypadek) i ponowne wypełnianie jest wtedy. Szkoda - miałem nadzieję, że to może być ukryte w metodzie. – Dave

+0

Wystarczy, że dodasz (dla przyszłych użytkowników), że w przypadku pokrewnego pytania na temat stwierdzeń niebędących pakietami, wartości nie muszą być ponownie wypełniane, zgodnie z tą dokumentacją: http://docs.oracle.com/javase/7/ docs/api/java/sql/PreparedStatement.html # clearParameters() – Dave

0

co to jest wiadomość wyjątku? Nie wiem, czy to się nie udało z powodu problemu z połączeniem mysql. Ponadto nie sądzę, że dobrze jest przetworzyć długą prośbę. Możesz uruchomić go wiele razy, wykonując kawałek po kawałku, aby osiągnąć swój cel.

+0

Odpowiedział na to w komentarzach do pytania. Na przyszłość nie należy zamieszczać komentarzy/pytań jako odpowiedzi. – Dave