We have a service that @Statefull . Most data operations are atomic, but within a certain set of functions. We want to run multiple native queries within the same transaction.
We introduced the EntityManager transaction persistence context. When creating a "bunch" of ordinary objects using em.persist() , everything works fine.
But when using its own queries (some tables are not represented by any @Entity ), Hibernate does not start them in a single transaction, but basically uses ONE transaction for each query.
So, I already tried to use manual records START TRANSACTION; and COMMIT; , but it seems to intervene in transactions, hibernate uses to save entities when mixing its own queries and calls of constant duration.
@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(); } }
Everything inside this method should happen within a single transaction. Is this possible with Hibernate? When debugging, it is clearly seen that each statement occurs “independently” from any transaction. (Ie Changes are dumped to the database immediately after each statement.)
I checked the example below with minimal setup to rule out any other problem factors (the rows are only for checkpoints to view the database after each 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(); } }
Sleep mode is configured as follows:
<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>
And the result is the same as in autocommit mode: after each native query, the database (viewing contents from the second connection) is immediately updated.
The idea of using a transaction using manuall leads to the same result:
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(); }