Hibernate实体管理器在查询之前自动刷新并在事务中将更改提交给数据库 [英] Hibernate Entity manager auto flush before query and commit changes to DB in transaction

查看:451
本文介绍了Hibernate实体管理器在查询之前自动刷新并在事务中将更改提交给数据库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Jboss AS 6.0.0 final上使用Hibernate 3.6.0和JPA 2。
在我的EJB中,有一种方法更新实体值并对其进行一些查询。整个方法在BMT交易中运行。如果有任何失败,所有更改应该回滚并且不提交给DB。



数据库是mySql。

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

EJB




$ @Stateless(mappedName =MyManagementBean)公共类MyManagement实现MyManagementLocal,MyManagementRemote {

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

/ **
*默认构造函数。
* /
public MyManagement(){
// TODO自动生成的构造函数存根
}

public void dosomething(String id)throws Exception
{

尝试{
utx.begin();
em = emf.createEntityManager();

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

line.setStatus(R);

Stromg q + =从Myline as line;
//自动刷新在这里应用并直接提交到DB ...
Iterator iter = em.createQuery(q).getResultList()。iterator();

em.flush();
utx.commit(); //更改只应在此
之后提交
catch(Exception e){
e.printStackTrace();
if(utx!= null)utx.rollback();
throw e; //或显示错误消息
}
finally {
em.close();
}
}
}

persistence.xml

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

<属性>
< property name =hibernate.connection.defaultNCharvalue =true/>
< property name =hibernate.dialectvalue =org.hibernate.dialect.MySQLMyISAMDialect/>
< property name =hibernate.ejb.cfgfilevalue =META-INF / hibernate.cfg.xml/>
< / properties>
< / persistence-unit>
< /余辉>

hibernate.cfg.xml

 <?xml version =1.0encoding =UTF-8?> 
<!DOCTYPE hibernate-configuration PUBLIC
- // Hibernate / Hibernate配置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>


<! - 将所有执行的SQL回复到stdout - >
< property name =show_sql> true< / property>

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


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

mysql-ds.xml

 <数据源> 

< 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>
<用户名>用户< /用户名>
<密码> pwd< /密码>
< exception-sorter-class-name> org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter< / exception-sorter-class-name>
<元数据>
< type-mapping> mySQL< / type-mapping>
< / metadata>
< / local-tx-datasource>
< / datasources>

经过进一步调查,我发现当有刷新时,肮脏的更改会被写入并提交直接到DB。如果我删除flush(),一切工作正常。然而,在查询之前有系统触发刷新,我认为这是必要的。



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



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

解决方案

问题已解决。
原因是默认情况下,mysql中的表使用 MyISAM 引擎,并且使用此引擎的表不支持事务。
将表切换为 innoDB 使事情起作用。
希望这对任何人都有用,所以他们不会像我那样浪费时间。 :(

I am using Hibernate 3.6.0 with JPA 2 on Jboss AS 6.0.0 final. In an EJB of mine, there's a method which updated entity values and do some query on it. The whole method is running in a BMT transaction. If anything fails, all changes should be rollback and not committed to DB.

The Database is mySql.

Before running JPA query, JPA will auto flush the changed states to DB to prevent any stale data from returning. However, within my method, the auto-flush directly update and commits the changes to DB and even something went wrong afterwards, the changes are not rollback. So I would like to ask if there's wrong configuration in my set up or this is a bug or something.

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>

Upon further investigating, I found out that when ever there's a flush, the dirty changes are written and committed to DB directly. If I remove the flush(), everything works fine. However, there are system triggered flush before query and I think it's necessary.

It seems to me that the db is auto-commited. I have tried to set the property hibernate.connection.autocommit to false but the problem just persist and a EJB warning of violating spec is prompted.

UPDATE: The cause should come from mysql. As if I switch to mssql server, the problem goes away.I also tried mysql with xa-datasource , still no luck...

解决方案

Problem resolved. The cause is that tables in the mysql is using MyISAM engine by default and tables using this engine do not support transaction. Switching tables to innoDB make thing works. Hope this would be useful for anyone, so they will not waste as much time as I did. :(

这篇关于Hibernate实体管理器在查询之前自动刷新并在事务中将更改提交给数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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