Hibernate的nativeQuery - 交易? [英] Hibernate nativeQuery - Transaction?

查看:443
本文介绍了Hibernate的nativeQuery - 交易?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有一个服务,它是 @Statefull 。大部分数据操作都是原子操作,但是在一组特定的函数中,我们希望在一个事务中运行多个原生查询



我们将 EntityManager 注入到一个事务范围的持久化上下文中。当创建一堆普通的实体时,使用 em.persist()一切正常。



但是,当使用本机查询时(某些表不是由任何 @Entity 表示),Hibernate不会在因此,我已经尝试使用手动 START TRANSACTION; COMMIT; 条目 - 但是这似乎干扰了事务处理,当混合原生查询和持久性调用时,hibernate用于保存实体。

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






$ b

此方法内的所有内容都应在一个事务中发生。这可能与休眠?
调试时,清楚地看到每个语句都发生独立于任何事务。 (即在每个语句后立即刷新数据库)。

最小的设置,以消除问题的任何其他因素(字符串只是为了在每个查询后查看数据库的断点):

  @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配置如下:

 < persistence-unit name =test> 
< provider> org.hibernate.jpa.HibernatePersistenceProvider< / provider>
< jta-data-source> java:jboss / datasources / test< / jta-data-source>

<属性>
< property name =hibernate.dialectvalue =org.hibernate.dialect.MySQL5InnoDBDialect/>

< property name =hibernate.transaction.jta.platform
value =org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform/>

< property name =hibernate.archive.autodetectionvalue =true/>
< property name =hibernate.jdbc.batch_sizevalue =20/>
< property name =connection.autocommitvalue =false/>
< / properties>
< / persistence-unit>

结果与自动提交模式相同:在每个本地查询之后,数据库(查看内容从第二个连接)立即更新。




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

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


解决方案

使用容器管理的交易,那么您需要添加交易政策太:

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



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


  • DataSource以自动提交模式运行,因此每个语句都在分离的事务中执行

  • EntityManager没有用@Transactional配置,但是只有查询可以运行,因为任何DML操作最终都会抛出一个事务
    $ b $ p
    $ b

    让我们回顾一下,您已经设置了以下Hibernate属性:

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





    您也可以使用:

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


    $根据您当前的应用服务器,b $ b

    或其他策略。

    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.

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

    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.

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

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

    • the DataSource is running in auto-commit mode, hence each statements is executed in a seprated 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.

    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
    

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

    You could also use the:

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

    or other strategy according to your current Application Server.

    这篇关于Hibernate的nativeQuery - 交易?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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