我的用例如下: 创建应用程序用户(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'。
我已经在没有 native 查询的情况下测试了 @Transactional 行为,它按预期工作(当我抛出 RuntimeException 并且没有数据插入数据库时,事务会回滚)
在调试时,我发现持久操作在正在运行的事务中调用时会延迟执行。
native 查询似乎立即创建并执行一个PreparedStatement(至少我没有找到任何类型的队列。
我想我可能无法获得 hibernate native 查询和 Spring 事务之间的交互,但是我花时间阅读了有关事务和 native 查询的 Spring 和 Hibernate 文档,但没有找到任何对我有帮助的内容。
也许有比 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/