我试图推进我们的应用程序。现在它在Glassfish 3,JAVA EE 6下运行,并使用Hibernate 3作为JPA实现。 我写了一个例子,显示了我对交易的问题。在某些环境中,应用程序需要手动调用实体管理器flush()方法。但即使在JTA环境中,会发生的事情是flush()导致底层数据库的物理提交(我们使用ojdbc6.jar JDBC驱动程序连接到ORACLE X / XI)。这不是预期的行为,因为JDBC事务应该加入JTA事务。如果在flush()之后由EJB引发异常,则应该回滚刷新的数据。 在Hibernate 3中,一切都很完美。在Hibernate 4.3.5中它没有。
调试Hibernate 4.3代码我发现了这个
package org.hibernate.jpa.internal.EntityManagerImpl
@Override
protected Session internalGetSession() {
if ( session == null ) {
...
SessionBuilderImplementor sessionBuilder = internalGetEntityManagerFactory().getSessionFactory().withOptions();
--->>>>>> sessionBuilder.autoJoinTransactions( getTransactionType() != PersistenceUnitTransactionType.JTA ); <<<<<<-----
session = sessionBuilder.openSession();
}
return session;
}
这导致org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl.attemptToRegisterJtaSync()方法进入此块并跳过与JTA平台的同步..
....
final JoinStatus joinStatus = currentHibernateTransaction.getJoinStatus();
if ( joinStatus != JoinStatus.JOINED ) {
// the transaction is not (yet) joined, see if we should join...
---->>>>> if ( !transactionContext.shouldAutoJoinTransaction() ) { <<<<<<----
// we are supposed to not auto join transactions; if the transaction is not marked for join
// we cannot go any further in attempting to join (register sync).
if ( joinStatus != JoinStatus.MARKED_FOR_JOINED ) {
if (isDebugging) {
LOG.debug( "Skipping JTA sync registration due to auto join checking" );
}
return;
}
}
}
我尝试调试Hibernate 5,这里AutoJoinTransaction问题消失了,大部分事务代码都被重写了。无论如何,flush()问题仍然存在。
我写了一个小例子来演示它。
@Stateless
public class BaseServicesAdapterImpl implements BaseServicesAdapterInterface {
@PersistenceContext
protected EntityManager em;
@Resource SessionContext sessionContext;
public EntityManager getEm() {
return em;
}
public void setEm(EntityManager em) {
this.em = em;
}
@Override
public String test() {
persistEntityAndFlush();
return "finished";
}
private void persistEntityAndFlush() {
persistEntityAndFlush("TST", new Integer(5), new Long(-1), new Long(-1),
new Date(), "", null, new Date(), new Integer(10), "test transaction",
null, null, null, "");
}
private Long persistEntityAndFlush(String tipoProcesso, Integer tpEntita, Long idEntita, Long progr,
Date date, String stato, String subStato, Date dtStato, Integer ggTimer,
String descrizione, String idPrcPerif1, String idPrcPerif2, String idPrcPerif3, String chiave1) {
Long idProcesso = 0L;
TestEntity testEntity = new TestEntity();
testEntity.setTpEntita(tpEntita);
testEntity.setIdEntita(idEntita);
testEntity.setIdProcesso(idProcesso);
//.....
getEm().persist(testEntity);
//***** THIS FLUSH COMMITS THE DATA *****
getEm().flush();
throw new RuntimeException("Too late?");
}
}
这是perstistence.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<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="test_pu" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>dsName</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="none" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="false" />
<property name="hibernate.use_sql_comments" value="false" />
<property name="hibernate.generate_statistics" value="false" />
<property name="hibernate.ejb.metamodel.generation" value="disabled" />
<!-- removing this does not affect anything -->
<property name="hibernate.connection.release_mode" value="after_transaction" />
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform" />
</properties>
</persistence-unit>
</persistence>
我错过了什么? 任何帮助将不胜感激。 提前谢谢,
David Obber
答案 0 :(得分:1)
我的错!我错过了resource-ref元素! 我不清楚为什么这会导致问题,但添加它就解决了它。
<servers>
<server config-ref="server-config" name="server">
<!-- WITH THE FOLLOWING LINE THE TRANSACTION PROBLEM DISAPPEARS -->
<resource-ref ref="MyDataSource"></resource-ref>
</server>
</servers>``
答案 1 :(得分:0)
好吧,我看到你使用EJB,EJB中的默认事务模式是容器管理事务(CMT),在这种模式下,管理事务的责任来自EJB容器。它根据CMT模式中每个Session Beans方法的事务属性打开,关闭,中止。
@TransactionManagement ( TransactionManagementType . CONTAINER )
public class YourClass
请参阅Bean管理事务 - BMT
@TransactionManagement ( TransactionManagementType . BEAN )
public class YouClass
使用BMT,您可以打开,关闭,中止等,责任来自您的应用程序