如何在同一个Hibernate事务中运行本机SQL查询? [英] How to run native SQL queries in the same Hibernate transaction?

查看:172
本文介绍了如何在同一个Hibernate事务中运行本机SQL查询?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有一个 @Statefull 的服务。大多数Data-Operations都是原子的,但在一组函数中我们希望在一个事务中运行多个本机查询

We have a Service which is @Statefull. Most of the Data-Operations are atomic, but within a certain set of functions We want to run multiple native queries within one transaction.

我们使用事务范围的持久化上下文注入 EntityManager 。在创建正常实体的束时,使用 em.persist()一切正常。

We injected the EntityManager with a transaction scoped persistence context. When creating a "bunch" of normal Entities, using em.persist() everything is working fine.

但是当使用本机查询(某些表没有由任何 @Entity 表示)时,Hibernate不会在其中运行它们相同的交易,但基本上每个查询使用一个交易。

But when using native queries (some tables are not represented by any @Entity) Hibernate does not run them within the same transaction but basically uses ONE transaction per query.

所以,我已经尝试使用手动 START TRANSACTION; COMMIT; 条目 - 但这似乎干扰了事务,hibernate在混合本机查询和持久性调用时用于持久化实体。

So, I already tried to use manual START TRANSACTION; and COMMIT; entries - but that seems to interfer with the transactions, hibernate is using to persist Entities, when mixing native queries and persistence calls.

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

此方法中的所有内容都应在一个事务中发生。这可能与Hibernate一起使用吗?
调试它时,可以清楚地看到每个语句都与任何事务独立发生。 (即每次声明后都会立即将更改刷新到数据库。)

Everything inside this method should happen within one transaction. Is this possible with Hibernate? When debugging it, it is clearly visible that every statement happens "independent" of any transaction. (I.e. Changes are flushed to the database right after every statement.)

我测试了下面给出的示例最小化设置以消除问题上的任何其他因素(字符串仅用于在每次查询后检查数据库的断点):

i've tested the bellow given example with a minimum setup in order to elimnate any other factors on the problem (Strings are just for breakpoints to review 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();
    }
}

Hibernate配置如下:

Hibernate is configured like this:

<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 outcome is the same as with autocommit mode: After every native query, the database (reviewing content from a second connection) is updated immediately.

以手动方式使用交易的想法导致相同的结果:

The idea of using the transaction in a manuall way 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();
    }


推荐答案

如果你不这样做使用容器管理的交易然后你需要添加交易政策:

In case you don't use container managed transactions then you need to add the transaction policy too:

@Stateful
@TransactionManagement(value=TransactionManagementType.CONTAINER)
@TransactionAttribute(value=REQUIRED)

我在两种情况下只看到过这种现象:

I have only seen this phenomenon in two situations:


  • DataSource 正在自动提交模式下运行,因此每个语句都在一个单独的事务中执行

  • EntityManager 未配置 @Transactional ,但之后只能运行查询因为任何DML操作都会最终抛出一个事务所需的异常。

  • the DataSource is running in auto-commit mode, hence each statement is executed in a separate transaction
  • the EntityManager was not configured with @Transactional, but then only queries can be run since any DML operation would end-up throwing a transaction required exception.

让我们回顾一下你设置了以下Hibernate属性:

Let's recap you have set the following Hibernate properties:

hibernate.current_session_context_class=JTA
transaction.factory_class=org.hibernate.transaction.JTATransactionFactory
jta.UserTransaction=java:comp/UserTransaction

必须使用Application Server UserTransaction JNDI命名密钥设置最终属性。

Where the final property must be set with your Application Server UserTransaction JNDI naming key.

你也可以使用:

hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JBossTransactionManagerLookup

或根据您当前的Java EE Application Server的其他策略。

or some other strategy according to your current Java EE Application Server.

这篇关于如何在同一个Hibernate事务中运行本机SQL查询?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆