我的用例如下:创建应用程序用户(EntityManager.persist)时,我还必须创建一个数据库用户并授予他权限(这就是我需要休眠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 以及 DB 用户(user1@localhost)。
所有的 nativeQueries 都被执行并立即一一提交。由于它们已提交,因此无法回滚。我的配置中的任何地方都没有设置自动提交参数,所以我假设它是“假”,如 Hibernate 文档中所见。
我已经在没有本机查询的情况下测试了 @Transactional 行为,它按预期工作(当我抛出 RuntimeException 并且没有数据插入数据库时,事务被回滚)
在调试时,我发现持久化操作在正在运行的事务中调用时会延迟执行。
本机查询似乎立即创建并执行 PreparedStatement(至少我没有找到任何类型的队列。
我想我可能无法获得 hibernate 本机查询和 Spring 事务之间的交互,但是我花时间阅读了有关事务和本机查询的 Spring 和 Hibernate 文档,但没有找到任何对我有帮助的东西。
也许有比本机查询更好的方法来创建数据库用户并授予权限(尽管我没有找到)
以下是我的应用程序配置:
应用程序上下文.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>
使用的库:
- 休眠 4.1.6.FINAL
- Spring 3.2.2.RELEASE
- mysql-connector-java-5.1.21
- MySQL 5.5