2013-08-13 7 views
12

Sto tentando di utilizzare Hibernate per un'applicazione multi thread in cui ogni thread recupera un oggetto e tenta di inserirlo in una tabella. Il mio codice appare come di seguito. Sono presenti oggetti Session di sospensione locali per thread e in ogni InsertData faccio startTransaction e commit.Come usare Hibernate in un'applicazione multi-thread?

Il problema che sto affrontando è che molte volte ottengo "org.hibernate.TransactionException: nidificato operazioni non supportate"

Dato che io sono nuovo di ibernazione non so se quello che sto facendo è corretto o non? Per favore fatemi sapere qual è il modo corretto di utilizzare la sospensione in un'app multi-thread e come evitare l'eccezione sopra menzionata.

Grazie

public class Worker extends Thread { 
private Session session = null; 

Worker() { 
    SessionFactory sf = HibernateUtil.getSessionFactory(); // Singleton 
    session = sf.openSession(); 
    session.setFlushMode(FlushMode.ALWAYS); 
} 

public void run() { 
    // Some loop which will run thousand of times 
    for (....) 
    { 
     InsertData(b); 
    } 
    session.close(); 
} 

// BlogPost Table has (pk = id AutoGenerated), dateTime, blogdescription etc. 
private void InsertData(BlogPost b) { 
    session.beginTransaction(); 
    Long id = (Long) session.save(b); 
    b.setId(id); 
    session.getTransaction().commit(); 
} 
} 

mio file di sospensione di configurazione è c3p0.min_size=10 e c3p0.max_size=20

+0

Si suppone che sia 'b.setId()'? –

+0

Sì, l'ho appena corretto. Si è verificato un errore durante il tentativo di creare un esempio minimo del mio codice effettivo. – Rahul

risposta

10

Con session-oggetti-per-thread, fintanto che non si condivide oggetti di sessione tra più thread, si andrà bene .

L'errore che si riceve non è correlato all'utilizzo multithread o alla gestione della sessione. L'utilizzo di session.save() e l'impostazione esplicita dell'ID non sono corretti.

Senza vedere la mappatura per BlogPost la sua difficile da dire, ma se avete detto Hibernate utilizzare il campo id come chiave primaria, e si utilizza il generatore nativo per le chiavi primarie, il tutto quello che dovete fare è questo :

session.beginTransaction(); 
session.persist(b); 
session.flush(); // only needed if flush mode is "manual" 
session.getTransaction().commit(); 

Hibernate riempirà l'ID per voi, persist() causerà l'inserto avvenga entro i limiti della transazione (save() non si preoccupa transazioni). Se la modalità a livello non è impostata su manuale, non è necessario chiamare lo flush() poiché lo gestirà direttamente da Transaction.commit().

Si noti che con persist(), l'ID di BlogPost non è garantito per essere impostato fino a quando la sessione viene svuotata, che va bene per il vostro uso qui.

per gestire gli errori con garbo:

try { 
    session.beginTransaction(); 
    try { 
     session.persist(b); 
     session.flush(); // only needed if flush mode is "manual" 
     session.getTransaction().commit(); 
    } catch (Exception x) { 
     session.getTransaction().rollback(); 
     // log the error 
    } 
} catch (Exception x) { 
    // log the error 
} 

A proposito, ho suggerendo facendo BlogPost.setId() privato, o un pacchetto visibile. È molto probabilmente un errore di implementazione se un'altra classe imposta esplicitamente l'ID (assumendo nuovamente il generatore nativo e id come chiave primaria).

+1

Grazie Jason, non ho avuto rollback() a causa del quale un'eccezione precedente stava lasciando una transazione aperta per il thread e la successiva beginTransation utilizzata per generare "TransactionException". – Rahul