本机查询executeUpdate似乎在Spring事务中提交数据

时间:2015-04-01 12:26:03

标签: mysql spring hibernate transactions hibernate-native-query

我的用例如下: 在创建应用程序用户(EntityManager.persist)时,我还必须创建一个DB用户并授予他权限(这就是我需要hibernate nativeQuery的原因)。

我有一个Spring @Transactional方法,它通过两个调用调用我的DAO:

@Transactional
public Integer createCompany(Company company) throws Exception {
    companyDao.createReportUser(ReportUser user);
    ...
}

我的DAO方法如下所示:

getEm().persist(companyReportsUser);
getEm().createNativeQuery("CREATE USER user1@localhost IDENTIFIED BY :password").setParameter("password", password).executeUpdate();
getEm().createNativeQuery("GRANT SELECT ON appdb.v_company TO user1@localhost").executeUpdate();
//several grants

现在,只要执行 executeUpdate()的第一行,我就可以在数据库中看到持久化的companyReportsUser以及数据库用户(user1 @ localhost)。

执行所有nativeQueries并立即逐个提交。由于它们被提交,因此无法回滚。 我的配置中的任何位置都没有设置自动提交参数,因此我认为它是' false' ,如Hibernate文档中所示。

  1. 我在没有本机查询的情况下测试了@Transactional行为,并且它按预期工作(当我抛出RuntimeException并且没有数据插入数据库时​​事务被回滚)

  2. 调试时我发现持久操作在正在运行的事务中调用时会延迟执行。

  3. 原生查询似乎立即创建并执行PreparedStatement(至少我没有找到任何类型的队列。

  4. 我想我可能没有得到hibernate本机查询和Spring事务之间的交互,但是我花了我的时间阅读关于事务和本机查询的Spring和Hibernate文档,并没有找到任何有用的东西我

  5. 也许有更好的方法来创建数据库用户并授予权限而不是本机查询(虽然我没有找到)

  6. 以下是我的应用程序配置:

    的applicationContext.xml

    <tx:annotation-driven transaction-manager="txManager" />
    
    <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory">
            <ref local="entityManagerFactory" />
        </property>
    </bean>
    
    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="persistenceUnitName" value="domainPU" />
        <property name="loadTimeWeaver">
            <bean
                class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
        </property>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
        </property>
    </bean>
    
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="${db.url}" />
        <property name="username" value="${db.user.name}" />
        <property name="password" value="${db.user.password}" />
        <property name="validationQuery" value="select 1 as dbcp_connection_test" />
        <property name="testOnBorrow" value="true" />
    </bean>
    

    的persistence.xml

    <persistence 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_1_0.xsd" version="1.0">
    <persistence-unit name="domainPU" transaction-type="RESOURCE_LOCAL">
    
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
    
        <class>com.domain.Entity1</class>
        ....
    
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
    
        <properties>
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
            <property name="hibernate.jdbc.batch_size" value="100"></property>
            <property name="hibernate.order_inserts" value="true"></property>
            <property name="hibernate.order_updates" value="true"></property>
    
            <property name="hibernate.c3p0.min_size" value="5"></property>
            <property name="hibernate.c3p0.max_size" value="30"></property>
            <property name="hibernate.c3p0.timeout" value="300"></property>
            <property name="hibernate.c3p0.max_statements" value="100"></property>
            <property name="hibernate.c3p0.idle_test_period" value="${hibernate.c3p0.idle_test_period}"></property>
        </properties>
    </persistence-unit>
    

    使用的图书馆:

    • Hibernate 4.1.6.FINAL
    • Spring 3.2.2.RELEASE
    • MySQL的连接器的Java-5.1.21
    • MySQL 5.5

1 个答案:

答案 0 :(得分:3)

在深入研究MySQL中的事务处理方式后,我找到了答案:

问题出在本机sql查询中的特定语句中。

来自MySQL文档:

  13.3.3导致隐含提交的陈述

     
      
  • 定义或修改数​​据库对象的数据定义语言(DDL)语句(... CREATE TABLE,DROP DATABASE ...)

  •   
  • 隐式使用或修改mysql数据库中的表的语句( CREATE USER ,DROP USER和RENAME USER ..., GRANT ,REVOKE ,. ..)

  •   
  • ...

  •   

此处有更多详情:

http://dev.mysql.com/doc/refman/5.1/en/implicit-commit.html

我决定将该行动分为两部分:

  • 普通的hibernate语句(在事务中),
  • 原生查询语句

并为用户提供工具/操作,以便在出现问题时重新调用第二部分。

其他解决方案是迁移到支持DDL操作周围事务的其他RDBMS。