【问题标题】:Hibernate Entity manager auto flush before query and commit changes to DB in transaction休眠实体管理器在查询之前自动刷新并将更改提交到事务中的数据库
【发布时间】:2011-09-24 21:49:30
【问题描述】:

我在 Jboss AS 6.0.0 final 上使用 Hibernate 3.6.0 和 JPA 2。 在我的 EJB 中,有一种方法可以更新实体值并对其进行一些查询。整个方法在 BMT 事务中运行。如果有任何失败,所有更改都应该回滚,而不是提交到数据库。

数据库是 mySql。

在运行 JPA 查询之前,JPA 会自动将更改的状态刷新到 DB 以防止任何过时的数据返回。但是,在我的方法中,自动刷新直接更新并将更改提交到数据库,即使之后出现问题,更改也不会回滚。所以我想问一下我的设置是否有错误的配置或者这是一个错误或什么的。

EJB

@Stateless(mappedName = "MyManagementBean")
    @Local
    @TransactionManagement(TransactionManagementType.BEAN)


    public class MyManagement implements MyManagementLocal,MyManagementRemote {

        @PersistenceUnit(unitName="MyEjb") EntityManagerFactory emf;
        @Resource UserTransaction utx;
        @Resource SessionContext ctx;

        /**
         * Default constructor. 
         */
        public MyManagement () {
            // TODO Auto-generated constructor stub
        }

        public void dosomething(String id) throws Exception
        {

            try {
                utx.begin();    
                em = emf.createEntityManager();

                Myline line = em.find(Myline.class, id);

                line.setStatus("R");

            Stromg q += " from Myline as line ";             
                //auto flush apply here and directly committed to DB...
            Iterator iter = em.createQuery(q).getResultList().iterator();

                em.flush();
                utx.commit();// changes should only commit after this
            }
            catch (Exception e) {
                e.printStackTrace();
                if (utx != null) utx.rollback();
                throw e; // or display error message
            }
            finally {
                em.close();
            }       
        } 
}

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="MyEjb" transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>java:MyDS</jta-data-source>
        <class>com.quincy.entity.MyLine</class>

        <properties>
            <property name="hibernate.connection.defaultNChar" value="true"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLMyISAMDialect"/>
            <property name="hibernate.ejb.cfgfile" value="META-INF/hibernate.cfg.xml"/>
        </properties>
    </persistence-unit>
</persistence>

hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>


        <property name="transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</property>


        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>       

        <property name="hibernate.max_fetch_depth">3</property>


    </session-factory>
</hibernate-configuration>

mysql-ds.xml

<datasources>

<local-tx-datasource>
    <jndi-name>MyDS</jndi-name>
    <connection-url>jdbc:mysql://10.10.150.57:3306/myds</connection-url>
    <driver-class>com.mysql.jdbc.Driver</driver-class>
    <user-name>user</user-name>
    <password>pwd</password>
    <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
    <metadata>
       <type-mapping>mySQL</type-mapping>
    </metadata>
  </local-tx-datasource>
</datasources>

经过进一步调查,我发现只要有刷新,脏更改就会被写入并直接提交到数据库。如果我删除了 flush(),一切正常。但是,查询前有系统触发的刷新,我认为这是必要的。

在我看来,数据库是自动提交的。我尝试将属性hibernate.connection.autocommit 设置为false,但问题仍然存在,并提示违反规范的EJB 警告。

更新:原因应该来自mysql。好像我切换到mssql服务器,问题就消失了。我也用xa-datasource尝试了mysql,仍然没有运气......

【问题讨论】:

  • 既然你使用的是JTA,那么mySQL数据库的数据源配置是什么?特别是,您需要为 mySQL 使用 XA 驱动程序才能使事务登记工作。
  • @Clement P:感谢您的回复。我已更新以包含 jdbc 设置。 Mysql版本是5.0,我用的是mysql-connector-java-5.1.13

标签: hibernate transactions jpa-2.0 entitymanager hibernate-entitymanager


【解决方案1】:

entityManager FlushModeType 设置什么

void setFlushMode(FlushModeType flushMode) 
Set the flush mode that applies to all objects contained in the persistence context.

该方法采用此处定义的枚举。

Enum Constant Summary

AUTO
       (Default) Flushing to occur at query execution.



COMMIT
       Flushing to occur at transaction commit.

还可以尝试检查以下内容

@PersistenceContext(unitName="MyEJB") private EntityManager em

在声明实体管理器工厂之后。

【讨论】:

  • 如果我将刷新模式设置为 COMMIT,则不会发生刷新。但是,查询返回过时的数据。现在的问题是刷新直接提交对数据库的更改。它应该只刷新对 DB 的更改而不是提交。
  • 您不能先执行查询(数据同步),然后对特定行进行更改然后提交吗?
  • 没有。在查询过程中,有某种检查,可能会导致失败。在这种情况下,我希望更改回滚。据我了解,即使刷新模式设置为自动,更改也只会被刷新以对其他查询可见,但不会直接提交给数据库。所以我想知道我的配置是否做错了什么。 (这是我第一次使用JPA API,之前用的是native hibernate)
  • 经过进一步调查,我发现只要有刷新,脏更改就会被写入并直接提交到数据库。似乎 em 并没有真正绑定到事务。但是,我仍然无法解决。 ://
【解决方案2】:

问题已解决。 原因是mysql中的表默认使用MyISAM引擎,使用该引擎的表不支持事务。 将表切换到innoDB 使事情正常进行。 希望这对任何人都有用,所以他们不会像我那样浪费太多时间。 :(

【讨论】:

  • 也为我工作。要查看当前引擎,请使用 show table status;。要更改表的引擎,请使用 alter table table_name engine=InnoDB;
猜你喜欢
  • 2016-01-22
  • 2012-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-28
  • 2012-11-24
  • 2021-12-04
  • 1970-01-01
相关资源
最近更新 更多