2011-05-19 20 views
9

Ho due tabelle nel mio database MySQL, che sono stati creati in questo modo:JDBC: chiave esterna sulla PK creato stessa transazione

CREATE TABLE table1 (
    id int auto_increment, 
    name varchar(10), 
    primary key(id) 
) engine=innodb 

e

CREATE TABLE table2 (
    id_fk int, 
    stuff varchar(30), 
    CONSTRAINT fk_id FOREIGN KEY(id_fk) REFERENCES table1(id) ON DELETE CASCADE 
) engine=innodb 

(queste non sono le tavole originali Il punto è che la tabella2 ha una chiave esterna che fa riferimento alla chiave primaria nella tabella 1)

Ora nel mio codice, vorrei aggiungere voci a entrambe le tabelle all'interno di una transazione. Così mi sono messo autoCommit su false:

Connection c = null;   

    PreparedStatement insertTable1 = null; 
    PreparedStatement insertTable2 = null; 

    try { 
     // dataSource was retreived via JNDI 
     c = dataSource.getConnection(); 
     c.setAutoCommit(false); 

     // will return the created primary key 
     insertTable1 = c.prepareStatement("INSERT INTO table1(name) VALUES(?)",Statement.RETURN_GENERATED_KEYS); 
     insertTable2 = c.prepareStatement("INSERT INTO table2 VALUES(?,?)"); 

     insertTable1.setString(1,"hage"); 
     int hageId = insertTable1.executeUpdate(); 

     insertTable2.setInt(1,hageId); 
     insertTable2.setString(2,"bla bla bla"); 
     insertTable2.executeUpdate(); 

     // commit 
     c.commit(); 
    } catch(SQLException e) { 
     c.rollback(); 
    } finally { 
     // close stuff 
    } 

Quando eseguo il codice di cui sopra, ottengo un'eccezione:

MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails 

Sembra che la chiave primaria non è disponibile nella transazione prima di commettere.

Mi manca qualcosa qui? Penso davvero che la chiave primaria generata dovrebbe essere disponibile nella transazione.

il programma viene eseguito su un Glassfish 3.0.1 utilizzando mysql-connector 5.1.14 e MySQL 5.5.8

Ogni aiuto è molto apprezzato!

saluti, Hage

risposta

5

vi siete persi qualcosa per l'id aggiornato restituito, si deve fare in questo modo:

Long hageId = null; 

try { 
    result = insertTable1.executeUpdate(); 
} catch (Throwable e) { 
    ... 
} 

ResultSet rs = null; 

try { 
    rs = insertTable1.getGeneratedKeys(); 
    if (rs.next()) { 
     hageId = rs.getLong(1); 
    } 
... 
+0

Grazie! Funziona perfettamente ora. Ma qualcosa non mi è ancora chiaro: i miei tavoli erano vuoti prima di eseguire il codice. Quindi 'exececuteUpdate' ha restituito il numero di righe interessate (in questo caso 1) che è anche l'ID generato. Penso che questo avrebbe dovuto funzionare anche - inoltre avrebbe sollevato l'eccezione in una seconda corsa ... Oppure "getGeneratedKeys()" rende le chiavi disponibili? – hage

+0

L'ID della riga inserita inizia dall'ultima riga + 1, a meno che non si esegua un 'troncamento' sulla tabella, non verrà inizializzato su 0. – EricParis16

+0

+1 Sto cercando questa risposta per molto tempo –

1

Invece di utilizzare executeUpdate() utilizzano execute() e poi tornare la chiave primaria.

http://www.coderanch.com/t/301594/JDBC/java/Difference-between-execute-executeQuery-executeUpdate

Ma io non lavoro con db ... così ho potuto fare un errore

+0

Conosco le differenze tra i diversi metodi execute *(). Stavo solo cercando di ottenere la chiave nel modo sbagliato. Pensavo che executeUpdate() avrebbe restituito la chiave piuttosto che il numero di righe modificate quando è stato impostato 'Statement.RETURN_GENERATED_KEYS'. Ma grazie per la tua risposta comunque. – hage

Problemi correlati