dog*_*ose 8 java mysql hibernate jpa transactions
我们有一个服务@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();
}
}
Run Code Online (Sandbox Code Playgroud)
此方法中的所有内容都应在一个事务中发生.这可能与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();
}
}
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
结果与自动提交模式相同:在每次本机查询之后,数据库(查看来自第二个连接的内容)会立即更新.
以手动方式使用事务的想法导致相同的结果:
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();
}
Run Code Online (Sandbox Code Playgroud)
如果您不使用容器管理的事务,那么您还需要添加事务策略:
@Stateful
@TransactionManagement(value=TransactionManagementType.CONTAINER)
@TransactionAttribute(value=REQUIRED)
Run Code Online (Sandbox Code Playgroud)
我只在两种情况下看到过这种现象:
DataSource在运行自动提交模式,因此每个语句在单独的事务执行EntityManager没有配置用@Transactional的,但是它们的查询可以运行,因为任何DML操作将最终投掷所需的交易例外。让我们回顾一下您设置了以下 Hibernate 属性:
hibernate.current_session_context_class=JTA
transaction.factory_class=org.hibernate.transaction.JTATransactionFactory
jta.UserTransaction=java:comp/UserTransaction
Run Code Online (Sandbox Code Playgroud)
必须使用您的应用程序服务器 UserTransaction JNDI 命名键设置最终属性。
您还可以使用:
hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JBossTransactionManagerLookup
Run Code Online (Sandbox Code Playgroud)
或根据您当前的 Java EE Application Server 的其他策略。
| 归档时间: |
|
| 查看次数: |
14010 次 |
| 最近记录: |