mysql - native 查询executeUpdate似乎在Spring事务中提交数据

标签 mysql spring hibernate transactions hibernate-native-query

我的用例如下: 创建应用程序用户(EntityManager.persist)时,我还必须创建一个数据库用户并授予他权限(这就是我需要 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都被一一执行并立即提交。既然它们已经提交,就不能回滚。 我的配置中的任何位置都没有设置自动提交参数,因此我假设它是 Hibernate 文档中的'false'

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

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

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

  4. 我想我可能无法获得 hibernate native 查询和 Spring 事务之间的交互,但是我花时间阅读了有关事务和 native 查询的 Spring 和 Hibernate 文档,但没有找到任何对我有帮助的内容。

  5. 也许有比 native 查询更好的方法来创建数据库用户并授予权限(尽管我没有找到)

下面是我的应用程序配置:

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>

持久性.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-connector-java-5.1.21
  • MySQL 5.5

最佳答案

深入研究 MySQL 中事务的工作原理后,我找到了答案:

问题出在 native SQL 查询内的特定语句中。

来自 MySQL 文档:

13.3.3 Statements That Cause an Implicit Commit

  • Data definition language (DDL) statements that define or modify database objects (...CREATE TABLE, DROP DATABASE...)

  • Statements that implicitly use or modify tables in the mysql database (CREATE USER, DROP USER, and RENAME USER..., GRANT, REVOKE, ...)

  • ...

更多详细信息请参见:

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

我决定将该操作分为两部分:

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

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

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

关于mysql - native 查询executeUpdate似乎在Spring事务中提交数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29390821/

相关文章:

php - 尝试在 PHP 中更新数据库时出现 Mysql 错误,并重定向到 null 位置

java - Hibernate 的 Projections.countDistinct 会产生意想不到的结果

java - Hibernate:多重选择@OneToMany

mysql - 如何获取exists子句中的数据

php - 想要按类型转换排序但按值(value)排序

php - 如何在php中获取最大日期数据

java - junit 中的 @Transactional 注解 - spring 和 jms

spring - 从 Spring IO 下载/导入所有依赖项

spring - hibernate jconsole Spring 配置

java - 命名查询仅适用于 Hibernate 3?