EntityManager FLUSH

EntityManager: Comportamento del metodo Flush
G.Morreale

Introduzione:


Come ho accennato nel precedente articolo se si usa un EntityManager JTA la transazione è delimitata dall'inizio e fine di un metodo.
L'istruzione dell'EntityManager sulla quale vorrei fare chiarezza è l'operazione di flush. (metodo EntityManager.flush())

La principale funzione del flush, senza scendere nei dettagli relativi alle relazioni tra Entity, è quella di sincronizzare il persistenceContext con il database sottostante.

L'EntityManager può avere due tipologie di FlushMode

FlushModeType.AUTO(Default) - Il flush avviene non appena viene eseguita una query in automatico
FlushModeType.COMMIT - Il flush avviene solo sul commit della transazione.


Esempio

Supponiamo di avere l'entity Esempiotable dotato di due campi (id, testo)
e di eseguire il seguente codice, con opportune varianti:

        //FLUSHMODETYPE.COMMIT - Senza Flush
        em.setFlushMode(FlushModeType.COMMIT);
        Esempiotable es = em.find(Esempiotable.class, 1);
        es.setTesto("ciao");
        String nuovoTesto = es.getTesto();
        System.out.println(nuovoTesto);
        
        es = (Esempiotable) em.createQuery("SELECT Object(o) FROM Esempiotable o WHERE o.id = 1").getResultList().get(0);
        nuovoTesto = es.getTesto();        
        System.out.println(nuovoTesto);
        
 //em.flush();        LINEA COMMENTATA!!!!!
        nuovoTesto = es.getTesto();
        System.out.println(nuovoTesto);


Il codice precedente, usando come persistence provider hibernate, genera il seguente sql:

Hibernate: 
    select
        esempiotab0_.id as id48_0_,
        esempiotab0_.testo as testo48_0_ 
    from
        esempiotable esempiotab0_ 
    where
        esempiotab0_.id=?
ciao
Hibernate: 
    select
        esempiotab0_.id as id48_,
        esempiotab0_.testo as testo48_ 
    from
        esempiotable esempiotab0_ 
    where
        esempiotab0_.id=1
ciao
ciao

In sostanza disabilitando l'auto flushing e non chiamando esplicitamente il metodo flush non viene eseguita l'update che porterebbe alla modifica della riga corrispondente all'istanza dell'entity.
Nonostante ciò è possibile notare come il testo stampato sia sempre ciao perchè le modifiche anche se non riportate sul db sono ben presenti nel persistence context.

Altro caso:

          //FLUSHMODETYPE.COMMIT - Con Flush
        em.setFlushMode(FlushModeType.COMMIT);
        Esempiotable es = em.find(Esempiotable.class, 1);
        es.setTesto("ciao");
        String nuovoTesto = es.getTesto();
        System.out.println(nuovoTesto);
        
        es = (Esempiotable) em.createQuery("SELECT Object(o) FROM Esempiotable o WHERE o.id = 1").getResultList().get(0);
        nuovoTesto = es.getTesto();        
        System.out.println(nuovoTesto);
        
        em.flush();        
        nuovoTesto = es.getTesto();
        System.out.println(nuovoTesto);


Hibernate: 
    select
        esempiotab0_.id as id36_0_,
        esempiotab0_.testo as testo36_0_ 
    from
        esempiotable esempiotab0_ 
    where
        esempiotab0_.id=?
ciao
Hibernate: 
    select
        esempiotab0_.id as id36_,
        esempiotab0_.testo as testo36_ 
    from
        esempiotable esempiotab0_ 
    where
        esempiotab0_.id=1
ciao
Hibernate: 
    update
        esempiotable 
    set
        testo=? 
    where
        id=?
ciao


In questo caso l'update viene eseguita solo quando viene richiamato esplicitamente il metodo di sincronizzazione con il db (flush()).
        
         //FLUSHMODETYPE.AUTO - Con Flush
        em.setFlushMode(FlushModeType.AUTO);
        Esempiotable es = em.find(Esempiotable.class, 1);
        es.setTesto("ciao");
        String nuovoTesto = es.getTesto();
        System.out.println(nuovoTesto);
        
        es = (Esempiotable) em.createQuery("SELECT Object(o) FROM Esempiotable o WHERE o.id = 1").getResultList().get(0);
        nuovoTesto = es.getTesto();        
        System.out.println(nuovoTesto);
        
        em.flush();        
        nuovoTesto = es.getTesto();
        System.out.println(nuovoTesto);

Hibernate: 
    select
        esempiotab0_.id as id40_0_,
        esempiotab0_.testo as testo40_0_ 
    from
        esempiotable esempiotab0_ 
    where
        esempiotab0_.id=?
ciao
Hibernate: 
    update
        esempiotable 
    set
        testo=? 
    where
        id=?
Hibernate: 
    select
        esempiotab0_.id as id40_,
        esempiotab0_.testo as testo40_ 
    from
        esempiotable esempiotab0_ 
    where
        esempiotab0_.id=1
ciao
ciao

In questo caso l'update viene eseguito in automatico prima di eseguire una nuova query.
Il flush() richiamato esplicitamente in questo caso non deve provvedere alla sincronizzazione di null'altro, e quindi nello specifico esempio risulta inutile.

Conclusione

Un breve post per mostrare attraverso un esempio il comportamento del metodo flush in relazione al FlushModeType



No comments: