Wie werden native SQL-Abfragen in derselben Transaktion im Ruhezustand ausgeführt?

Wir haben einen Service, der @ i@Statefull. Die meisten Datenoperationen sind atomar, aber innerhalb eines bestimmten Funktionsumfangs möchten wir mehrere @ ausführenative queries innerhalb einer Transaktion.

Wir haben das @ gespritEntityManager mit einem transaktionsbezogenen Persistenzkontext. Wenn Sie eine "Gruppe" normaler Entitäten erstellen, verwenden Sieem.persist() alles funktioniert gut.

Aber bei Verwendung von systemeigenen Abfragen (einige Tabellen werden nicht durch ein @ dargestell@Entity) Hibernate führt sie nicht in derselben Transaktion aus, sondern verwendet grundsätzlich EINE Transaktion pro Abfrage.

Also, ich habe bereits versucht, manuellSTART TRANSACTION; undCOMMIT; entries - aber das scheint die Transaktionen zu stören. Der Ruhezustand wird verwendet, um Entities beizubehalten, wenn systemeigene Abfragen und Persistenzaufrufe gemischt werden.

@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();
   }
}

Alles in dieser Methode sollte innerhalb einer Transaktion geschehen. Ist das mit Hibernate möglich? Beim Debuggen ist deutlich zu erkennen, dass jede Anweisung "unabhängig" von einer Transaktion erfolgt. (Das heißt, Änderungen werden direkt nach jeder Anweisung in die Datenbank geschrieben.)

Ich habe das unten angegebene Beispiel mit einer minimalen Konfiguration getestet, um andere Faktoren für das Problem auszuschließen. (Zeichenfolgen dienen nur als Haltepunkte, um die Datenbank nach jeder Abfrage zu überprüfen.)

@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 ist folgendermaßen konfiguriert:

<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>

Und das Ergebnis ist dasselbe wie im Autocommit-Modus: Nach jeder systemeigenen Abfrage wird die Datenbank (die den Inhalt einer zweiten Verbindung überprüft) sofort aktualisiert.

Die Idee, die Transaktion manuell zu verwenden, führt zum gleichen Ergebnis:

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();
    }

Antworten auf die Frage(3)

Ihre Antwort auf die Frage