# PreparedStatement batch und getGeneratedKeys



## pups (25. Feb 2011)

Hallo,

ich habe 2 Tabellen. T2 hat einen FK auf T1. Nun füge ich mit preparedStatement und addBatch() einen haufen in T1. Jetzt rufe ich getGeneratedKeys() auf und kriege eine Liste von erzeugten Schlüsseln.

Nun nehme ich die in der Reihenfolge in der sie kommen und füge die Daten in T2 ein. Klappt alles wunderbar aber ich kann in der API nirgendswo den Satz finden, dass getGeneratedKeys die Schlüssel in der Reihenfolge zurückliefert wie sie in addBatch() gedacht gewesen wäre.

Also mit anderen Worten, ich will die zurückgelieferten Keys in der Software auf die eingefügten Daten mappen können, und der einzige Anhaltspunkt ist nunmal die Reihenfolge der Keys.

Darf ich das Annehmen oder ist das nur Zufall, dass das passt?

Danke vielmals


----------



## DerEisteeTrinker (28. Feb 2011)

Du kannst es annehmen, aber ob deine Annahme stimmt, siehst du erst, wenn das Licht angeht. Drauf verlassen würde ich mich nicht. Da ich nicht weiß, inwieweit du die Keys in der DB generierst, so würde ich vllt versuchen die Keys vorher in Java zu generieren und diese ebenfalls in einer LinkedList ablegen oder einer anderen reihenfolgen-bezogenen Collection und diese dann im Anschluß einfach in die T2 einzufügen.


----------



## pups (28. Feb 2011)

Danke für die Antwort.

Die Lösung mit Keys softwareintern vergeben fällt flach, da nicht ausgeschlossen werden kann, dass das Tool exclusiven Zugriff auf die DB hat.

Aber das Problem ist doch kein neues, besonders weltfremdes? Innerhalb einer Transaktion in mehrere Tabellen einfügen und dabei die referenzielle Integrität aufrecht erhalten, das sollte JDBC doch können. Ich will eben nur effizient mit dem Batchfeature arbeiten können.

Ich bin auch gern für andere Lösungen offen.

Trigger in einer DB sind Tabu (können sowieso nicht alle).

Also schieß(t) los. DANKE

p.s.

hier hab ich noch was gefunden:
java - Using getGeneratedKeys with batch inserts in MySQL with Connector/J - Stack Overflow
aber auch nur ein Testergebnis...


----------



## DerEisteeTrinker (1. Mrz 2011)

Dann stellt sich mir die Frage, warum ist es wichtig, dass die Daten aus T2 genau in der gleichen Reihenfolge wie in T1 stehen? Einem SQL-Statement bzw. der referenziellen Integrität ist das herzlich egal. Wenn du auf T1 iwo einen Index hast, dann kannst du eh nicht beeinflussen in welcher Reihenfolge die Daten abgelegt werden, denn du weißt nicht, wie deine Datenbank intern die Daten strukturiert.


----------



## pups (1. Mrz 2011)

Ich glaub da haben wir uns missverstanden... 

Also mein Programm hat Datensätze die effizient in die DB müssen. Diese Daten werden auf mehrere Tabellen verteilt (T1,T2 usw.).

Der Datensatz als Ganzes ist der Eintrag in T1 und der Eintrag in T2 mit dem Fremdschlüssel aus T1.

Die Reihenfolge in der Tabellen ist absolut egal. Es geht mir um die Reihenfolge der erzeugten Schlüssel in T1 und ob diese mit der Reihenfolge übereinstimmt, wie ich PreparedStatement.addBatch() aufgerufen habe.

Diese Funktion brauche ich, um den T2-Daten den richtigen FK zu geben.

Weißt du/ihr was ich meine?


----------



## DerEisteeTrinker (1. Mrz 2011)

Ich kann mir in etwa vorstellen was du meinst. Nur ist mir schleierhaft, wieso du auf die Reihenfolge bestehst. Du wirst doch sicher am Ende mit einem join oder einer Unterabfrage arbeiten oder etwa nicht?

Vllt kannst du mal eine mal einen beispielhaften Auszug der Tabellen vor und nach dem Einfügen geben, und genau aufzeigen, wo die Reihenfolge relevant ist.


----------



## pups (1. Mrz 2011)

Nee ich will keine weiteren Abfragen danach mehr machen.

Also mal ein Beispiel, wobei's am Javacode ersichtlicher ist.


```
PreparedStatement st1 = cn.prepareStatement("INSERT INTO t1 (a,b) VALUES (?,?)",Statement.RETURN_GENERATED_KEYS);
	PreparedStatement st2 = cn.prepareStatement("INSERT INTO t2 (FK_von_t1,c) VALUES (?,?)");
	for (Data data:dataCollection){
		st1.setString(1,data.getA());
		st1.setString(2,data.getB());
		st1.addBatch();
	}
	int[] results = st1.executeBatch();
	ResultSet rs = st1.getGeneratedKeys();
	if (dataCollection.getSize()!=rs.getMetaData().getSize())throw IrgendEineException(); // dann cn.rollback() usw...
	Iterator<String[]> iter = dataCollection.iterator(); // rs und dataCollection sind gleich lang wenn results alle erfolgreich sind
	while(rs.next()) {
		String[] data = iter.next();
		String key = rs.getString(1);
		st2.setString(1,key);  //hier wird die Reihenfolge wichtig
		st2.setString(2,data.getC());
		st2.addBatch();
	}
	st22.executeBatch();
```


----------



## DerEisteeTrinker (1. Mrz 2011)

*Klugscheißermodus ein*
in Zeile 10 Würde ich vor dem throw einen Zeilenumbruch machen
*Klugscheißermodus aus*

Zeile 13 und Zeile 16 funktionieren garantiert nicht. Ich nehme an, dass du Da aus dem String[] jedes Teil einzeln einfügst und mit dem FK versiehen möchtest.

Zur Topic:

also wenn der Quellcode in etwa den Sachverhalt wiederspiegelt und ich das richtig verstehe, dann würde ich sagen, dass du entweder den Entwicklern von Sun/Oracle vertraust und wartest, bis getGeneratedKeys mal falsch arbeitet oder du musst zwischendrin ein Select auf die eingefügten Daten machen, um die Keys zu erhalten und da kannst die Daten dann wieder zuordnen. Aber das musst du halt alles händisch machen.




> Nee ich will keine weiteren Abfragen danach mehr machen.



Datenspeicherung ohne Sinn? Ist das nicht verfassungswidrig (sry, der Scherz musste sein)


----------

