2016-05-26 12 views
0

Ich versuche, Aufzeichnungen zu Postgres-Tabelle einzufügen Prepared Statements, aber ich bin immer Fehler folgende während Insert-Anweisungen:Spring Batch insert/update auf Postgres vorbereitete Anweisung mit

[main] ERROR org.springframework.batch.core.step.AbstractStep - Encountered an error executing step someStep in job someJob 
org.springframework.dao.EmptyResultDataAccessException: Item 0 of 1 did not update any rows: [[[email protected],[email protected]] 
    at org.springframework.batch.item.database.JdbcBatchItemWriter.write(JdbcBatchItemWriter.java:202) 

Mein Schreiber ist:

package com.somepackage.writer; 

public class trialClass implements ItemPreparedStatementSetter<List<someORM>> { 

    @Override 
    public void setValues(List<someORM> itemList,java.sql.PreparedStatement ps) throws SQLException,EmptyResultDataAccessException { 
     try { 
    for (ORM item : itemList) { 
    for (int i = 0;i<itemList.size();i++) 
     { 
    ps.setInt(1, itemList.get(i).getPropOne());       
    ps.setString(2, itemList.get(i).getPropTwo()); 
    ps.setInt(3, itemList.get(i).getPropThree()); 
    ps.setInt(4, itemList.get(i).getPropFour()); 
    ps.addBatch(); 
} 
int[] rs = ps.executeBatch(); 
     } catch (Exception e) { 
    e.printStackTrace(); 
    }}} 

Meine xML-Datei ist so etwas wie dieses:

<beans:bean id="beanId" scope="step" 
       class="org.springframework.batch.item.support.CompositeItemWriter"> 
       <beans:property name = "delegates"> 
        <util:list> 
        <beans:ref bean= "someId"/> 
        <beans:ref bean= "someOtherId"/> 
        </util:list> 
       </beans:property> 
       </beans:bean> 

<beans:bean id = "someId" scope = "step" 
       class="org.springframework.batch.item.database.JdbcBatchItemWriter"> 
       <beans:property name="dataSource" ref="someSource" /> 
       <beans:property name="sql" value = "${fetch.somequery.sql}" > 
       </beans:property> 
       <beans:property name="itemPreparedStatementSetter" ref="someRef" /> 
     </beans:bean> 

ich erhalte Fehler nur während des Einfügens der Datensätze funktionieren die Aktualisierungen einwandfrei (Postgres-Tabelle hat Primärschlüssel in der ersten Spalte) (In beiden Fällen werden die Datensätze in die postgres-Tabelle eingefügt/aktualisiert, aber bei der Einfügung wird dieser Fehler immer noch angezeigt)

und ich bin mit Abfrage wie:

fetch.somequery.sql =INSERT INTO table1 (col1, col2, col3) SELECT ?,?,? WHERE NOT EXISTS (SELECT 1 FROM table1 WHERE col1= ?); 

aber wenn ich Ebene einfügen Abfrage verwende ich bin immer Fehler wie:

Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key violates unique constraint "table1_pkey" (seg576 sdw24:40000 pid=398877) 
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2062) 

ich habe dafür gesorgt, dass die Datensätze nicht sind duplizieren, sondern st krank bekommen diesen Fehler

Wo mache ich es falsch? Kann ich ORM verwenden, um Daten zu Postgres zu aktualisieren. Wenn ja, wie? Kann ich die jdbc-Vorlage verwenden, um Daten zu Postgres zu aktualisieren? Wenn ja, wie?

Wie behandelt man diese Ausnahme?

+0

Wie kann ich die überspringbare Ausnahmeklasse in Schritt –

Antwort

0

Der gesamte Datensatz muss nicht notwendigerweise ein Duplikat sein, um eine unique constraint zu verletzen. Die einzige (n) Spalte (n), die identisch sein müssen, sind diejenigen, die die Beschränkung umfassen. Hier sagt der Fehler, den Sie angegeben haben, dass es die table1_pkey Einschränkung ist, die beteiligt ist, so dass Sie die DDL für diese Einschränkung verweisen müssen, um die Spalten zu bestimmen.

Aus dem bereitgestellten Code ist es nicht möglich, sicher zu sagen, aber ich vermute, was passiert, ist, dass zwei Elemente in Ihrer Liste, für welche Eigenschaft in table1_pkey verwiesen wird, gleich sind.

Es ist im Allgemeinen am besten sequences für diese Art der Sache zu verwenden (vorausgesetzt, es ist eine einzige Spalte), die Postgres selbst bevölkern werden, so lange wie Sie es nur den Standardwert verwenden lassen (und haben den Standardwert richtig erhöhen die Reihenfolge - der serial Typ ist syntaktischer Zucker, der das automatisch tut).

Auch wenn es nur eine Spalte beteiligt ist, und es sollte den Primärschlüssel sein, kann er als solche inline deklariert werden, so etwas wie dies in den DDL: id serial primary key

Wenn mehrere Spalten beteiligt Es gilt das gleiche allgemeine Konzept, aber Sie würden den Primärschlüssel nicht ganz auf die gleiche Weise definieren (er würde später als Einschränkung definiert, da er aus einem Spaltentupel bestehen würde), und Sie müssten mehrere davon sicherstellen Sequenzen werden verwendet.

Antwort vom OP Kommentar:

Wenn die Datensätze bereits vorhanden sind, zu versuchen, sie wieder einzuführen die eindeutige Einschränkung definitorisch verletzen. Kombinieren Sie Einfüge- und Aktualisierungsfälle unter einer einzigen Einfügeoperation? Das wird nicht funktionieren. Updates und Einfügungen müssen getrennt sein. Sie können helfen, sich vor dem Vorhandensein in einer Einfügung zu schützen, indem Sie eine where exists Unterauswahl in der Einfügung hinzufügen, so dass die Einfügung, wenn sie existiert, eine Nicht-Operation ist. Die Updates müssten immer noch separat durchgeführt werden.

Die Ausnahme ist die upsert, die Postgre in 9.5 neu ist und passen, was Sie hier suchen.

Vom doc:

KONFLIKT aktualisierte eine atomare INSERT oder UPDATE Ergebnis gewährleistet; vorausgesetzt, es gibt keinen unabhängigen Fehler, ist eines dieser beiden Ergebnisse garantiert, auch bei hoher Parallelität. Dies wird auch als UPSERT - "UPDATE oder INSERT" bezeichnet.

+0

verwenden Die Datensätze, die ich zu aktualisieren versuche, sind eindeutig (ich habe es überprüft). Da diese Datensätze bereits in der Tabelle vorhanden sind und wenn ich versuche, "einzufügen" wird die DB einen Fehler werfen. Deshalb versuche ich jetzt einzufügen, wenn dieser Datensatz nicht existiert. In diesem Fall wird jedoch der neue eindeutige Datensatz in die Tabelle eingefügt, aber im Stapel wird der Fehler "EmptyResultDataAccessException" ausgegeben. Ich denke, die DB wirft etwas, was beim Batch-Prozess nicht erwartet wird. aber ich bin nicht in der Lage, diese Ausnahme zu fangen. –

0

Ich hatte ein ähnliches Problem einmal und es wird nicht von der Writer-Bean verursacht.

Das Problem, in meinem Fall war, weil ich einen nicht thread-sicheren Leser verwendet hatte, so meine Quelle lesen (aleatorischen) einige Itens mehr als einmal.

In Ihren Beispielquellen kann ich nur die Schreiberdeklarationen sehen.

Ich empfehle Ihnen, den Leser zu überprüfen, und wenn Sie ein paralleles Lesegerät benötigen, verwenden Sie das richtige oder erwägen Sie, sequenzielles Lesegerät zu verwenden.

+0

Sein Thread sicher –