Abbiamo un servizio che è @Statefull
. La maggior parte dei dati-Operazioni sono atomici, ma all'interno di un certo insieme di funzioni. Vogliamo eseguire più native queries
all'interno di una transazione.Hibernate nativeQuery - Transazione?
Abbiamo iniettato il EntityManager
con un contesto di persistenza con ambito transazione. Quando si crea un "mazzo" di entità normali, usando em.persist()
tutto funziona correttamente.
Ma quando si utilizzano le query native (alcune tabelle non sono rappresentate da qualsiasi @Entity
) Hibernate non le esegue all'interno della stessa transazione ma fondamentalmente utilizza UNA transazione per query.
Così, ho già cercato di utilizzare manuali START TRANSACTION;
e COMMIT;
voci - ma che sembra interferire con le operazioni, Hibernate sta usando a persistere entità, quando si mescolano le query nativi e le chiamate di persistenza.
@Statefull
class Service{
@PersistenceContext(unitName = "service")
private EntityManager em;
public void doSth(){
this.em.createNativeQuery("blabla").executeUpdate();
this.em.persist(SomeEntity);
this.em.createNativeQuery("blablubb").executeUpdate();
}
}
Tutto all'interno di questo metodo deve avvenire all'interno di una transazione. È possibile con Hibernate? Durante il debug, è chiaramente visibile che ogni affermazione avviene "indipendente" da qualsiasi transazione. (Ie I cambiamenti sono lavata al database dopo ogni affermazione.)
Ho testato il soffietto dato esempio con una configurazione minima per elimnate qualsiasi altro fattore sul problema (stringhe sono solo per i punti di interruzione a rivedere il database dopo ogni query):
@Stateful
@TransactionManagement(value=TransactionManagementType.CONTAINER)
@TransactionAttribute(value=TransactionAttributeType.REQUIRED)
public class TestService {
@PersistenceContext(name = "test")
private EntityManager em;
public void transactionalCreation(){
em.createNativeQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','b','c')").executeUpdate();
String x = "test";
em.createNativeQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','c','b')").executeUpdate();
String y = "test2";
em.createNativeQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('c','b','a')").executeUpdate();
}
}
Hibernate è configurato in questo modo:
<persistence-unit name="test">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>java:jboss/datasources/test</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="hibernate.transaction.jta.platform"
value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
<property name="hibernate.archive.autodetection" value="true" />
<property name="hibernate.jdbc.batch_size" value="20" />
<property name="connection.autocommit" value="false"/>
</properties>
</persistence-unit>
E il risultato è lo stesso che con modalità autocommit: dopo ogni nat quesito, il database (rivedere il contenuto da una seconda connessione) viene aggiornato immediatamente.
L'idea di utilizzare l'operazione in modo manuall conduce allo stesso risultato:
public void transactionalCreation(){
Session s = em.unwrap(Session.class);
Session s2 = s.getSessionFactory().openSession();
s2.setFlushMode(FlushMode.MANUAL);
s2.getTransaction().begin();
s2.createSQLQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','b','c')").executeUpdate();
String x = "test";
s2.createSQLQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','c','b')").executeUpdate();
String y = "test2";
s2.createSQLQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('c','b','a')").executeUpdate();
s2.getTransaction().commit();
s2.close();
}
Hai provato [questo] (http://stackoverflow.com/a/12969520/2749837) già in modo? – gantners
in alternativa puoi provare a interrompere l'ibernazione dalle modifiche di flussaggio al db chiamando prima getSession(). SetFlushMode (FlushMode.MANUAL), ma questa è solo un'ipotesi. – gantners
per la tua risposta. 'FlushMode.Manual' non ha alcun impatto sembra. Proverò la soluzione proposta sull'uso diretto di una sessione piuttosto che su 'em'. – dognose