【发布时间】:2014-11-02 23:40:04
【问题描述】:
我们有一个服务是@Statefull。大多数数据操作都是原子的,但是在一组特定的函数中我们希望在一个事务中运行多个native queries。
我们向EntityManager 注入了事务范围的持久性上下文。创建“一堆”普通实体时,使用em.persist() 一切正常。
但是当使用本机查询时(某些表没有由任何@Entity 表示)Hibernate 不会在同一个事务中运行它们,而是基本上每个查询使用一个事务。
所以,我已经尝试使用手动 START TRANSACTION; 和 COMMIT; 条目 - 但这似乎会干扰事务,当混合原生查询和持久性调用时,hibernate 用于持久化实体。
@Statefull
class Service{
@PersistenceContext(unitName = "service")
private EntityManager em;
public void doSth(){
this.em.createNativeQuery("blabla").executeUpdate();
this.em.persist(SomeEntity);
this.em.createNativeQuery("blablubb").executeUpdate();
}
}
此方法中的所有内容都应在一个事务中发生。 Hibernate可以做到这一点吗? 在调试它时,可以清楚地看到每条语句都“独立”于任何事务发生。 (即,在每条语句之后立即将更改刷新到数据库。)
我已经使用最低设置测试了下面给出的示例,以消除问题的任何其他因素(字符串仅用于在每次查询后检查数据库的断点):
@Stateful
@TransactionManagement(value=TransactionManagementType.CONTAINER)
@TransactionAttribute(value=TransactionAttributeType.REQUIRED)
public class TestService {
@PersistenceContext(name = "test")
private EntityManager em;
public void transactionalCreation(){
em.createNativeQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','b','c')").executeUpdate();
String x = "test";
em.createNativeQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','c','b')").executeUpdate();
String y = "test2";
em.createNativeQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('c','b','a')").executeUpdate();
}
}
Hibernate 是这样配置的:
<persistence-unit name="test">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>java:jboss/datasources/test</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="hibernate.transaction.jta.platform"
value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
<property name="hibernate.archive.autodetection" value="true" />
<property name="hibernate.jdbc.batch_size" value="20" />
<property name="connection.autocommit" value="false"/>
</properties>
</persistence-unit>
结果与自动提交模式相同:每次本机查询后,数据库(从第二个连接查看内容)立即更新。
以手动方式使用事务的想法导致相同的结果:
public void transactionalCreation(){
Session s = em.unwrap(Session.class);
Session s2 = s.getSessionFactory().openSession();
s2.setFlushMode(FlushMode.MANUAL);
s2.getTransaction().begin();
s2.createSQLQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','b','c')").executeUpdate();
String x = "test";
s2.createSQLQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','c','b')").executeUpdate();
String y = "test2";
s2.createSQLQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('c','b','a')").executeUpdate();
s2.getTransaction().commit();
s2.close();
}
【问题讨论】:
-
你试过this吗?
-
作为替代方案,您可以尝试通过调用 getSession().setFlushMode(FlushMode.MANUAL) 来阻止休眠将更改刷新到数据库,但这只是一个猜测。
-
感谢您的回复。
FlushMode.Manual似乎没有任何影响。我将尝试有关直接使用会话而不是em的建议解决方案。
标签: java mysql hibernate jpa transactions