Hi Jean-Baptiste,
We are using the following datasource factory:
admin@root()> bundle:services -p 265
OPS4J Pax JDBC Oracle Driver Adapter (265) provides:
----------------------------------------------------
objectClass = [org.osgi.service.jdbc.DataSourceFactory]
osgi.jdbc.driver.class = oracle.jdbc.OracleDriver
osgi.jdbc.driver.name = oracle
service.bundleid = 265
service.id = 300
service.scope = singleton
From that we then create an xa and a local datasource, using our own component
rather than pax jdbc config:
admin@root()> bundle:services -p 313
xxx-withheld-xxx (313) provides:
----
eig.datasource.dialect = org.hibernate.dialect.Oracle10gDialect
eig.datasource.id = events
eig.datasource.pool.connectionTimeout = 30000
eig.datasource.pool.maxLifetime = 1800000
eig.datasource.pool.maxPoolSize = 40
eig.datasource.type = ORACLE
eig.datasource.url = xxx-withheld-xxx
eig.datasource.user = xxx-withheld-xxx
objectClass = [javax.sql.DataSource]
service.bundleid = 313
service.id = 574
service.scope = singleton
----
eig.datasource.dialect = org.hibernate.dialect.Oracle10gDialect
eig.datasource.id = events
eig.datasource.pool.connectionTimeout = 30000
eig.datasource.pool.maxLifetime = 1800000
eig.datasource.pool.maxPoolSize = 40
eig.datasource.type = ORACLE
eig.datasource.url = xxx-withheld-xxx
eig.datasource.user = xxx-withheld-xxx
objectClass = [javax.sql.XADataSource]
service.bundleid = 313
service.id = 575
service.scope = singleton
Interestingly, I took Paul up on his suggestion to use the xa datasource - and
therefore also the xa JPAEntityManagerProviderFactory and TransactionControl
too – and that resolved the issue!
However it’s not really a solution for us. Firstly due to performance reasons
we require local transactions for some use cases and xa for others, so we don’t
have the option to use xa everywhere.
And secondly in order for xa transactions to work we had to temporarily disable
the karaf 4.4.3 eclipselink feature otherwise we get the following exception
when obtaining an EntityManager via the
org.osgi.service.transaction.control.JPAEntityManagerProvider.getResource()
method:
Caused by: java.lang.NoSuchMethodError:
org.osgi.service.jpa.EntityManagerFactoryBuilder.getPersistenceProviderName()Ljava/lang/String;
at
org.apache.aries.tx.control.jpa.xa.impl.JPAEntityManagerProviderFactoryImpl.setupTransactionManager(JPAEntityManagerProviderFactoryImpl.java:250)
~[?:?
at
org.apache.aries.tx.control.jpa.xa.impl.JPAEntityManagerProviderFactoryImpl.getProviderFor(JPAEntityManagerProviderFactoryImpl.java:220)
~[?:?]
at
org.apache.aries.tx.control.jpa.xa.impl.JPAEntityManagerProviderFactoryImpl.lambda$handleNormalDataSource$5(JPAEntityManagerProviderFactoryImpl.java:20
at
org.apache.aries.tx.control.jpa.common.impl.DelayedJPAEntityManagerProvider.getResource(DelayedJPAEntityManagerProvider.java:56)
~[?:?]
at
org.apache.aries.tx.control.jpa.common.impl.DelayedJPAEntityManagerProvider.getResource(DelayedJPAEntityManagerProvider.java:28)
~[?:?]
We tracked this down to a defective
org.osgi.service.jpa.EntityManagerFactoryBuilder being installed via the
eclipselink feature as declared in the official karaf
enterprise-4.4.3-features.xml file – the javax.persistence bundle in particular:
<feature name="eclipselink" description="Eclipselink JPA persistence engine
support" version="2.7.11">
<details>Eclipselink persistence engine.</details>
<feature version="[2,3)">jpa</feature>
<bundle
dependency="true">mvn:org.eclipse.persistence/javax.persistence/2.2.0</bundle>
<feature version="[2,3)">transaction</feature>
<bundle>mvn:org.eclipse.persistence/org.eclipse.persistence.jpa/2.7.11</bundle>
<bundle>mvn:org.eclipse.persistence/org.eclipse.persistence.core/2.7.11</bundle>
<bundle>mvn:org.eclipse.persistence/org.eclipse.persistence.asm/9.3.0</bundle>
<bundle>mvn:org.eclipse.persistence/org.eclipse.persistence.antlr/2.7.11</bundle>
<bundle>mvn:org.eclipse.persistence/org.eclipse.persistence.jpa.jpql/2.7.11</bundle>
<bundle>mvn:org.apache.aries.jpa/org.apache.aries.jpa.eclipselink.adapter/2.7.3</bundle>
<capability>
osgi.service;objectClass=javax.persistence.spi.PersistenceProvider;effective:=active;javax.persistence.provider=org.eclipse.persistence.jpa.PersistenceProvider
</capability>
</feature>
I’m using the word “defective” because the EntityManagerFactoryBuilder is
indeed missing the getPersistenceProviderName() method even though it exports
the package as version 1.1.0 – whereas I believe the method should exist from
that version onwards. From the bundle manifest:
Export-Package: javax.persistence;jpa="2.2";version="2.2.0",javax.pers
istence.criteria;jpa="2.2";version="2.2.0",javax.persistence.metamode
l;jpa="2.2";version="2.2.0",javax.persistence.spi;jpa="2.2";version="
2.2.0",org.osgi.service.jpa;version="1.1.0"
We’ve no idea how to prevent the org.osgi.service.jpa package from the
javax.persistence bundle from being imported into other bundles in preference
to the same package from bundles (that contain the EntityManagerFactoryBuilder
with the getPersistenceProviderName() method). For example these bundle contain
the correct class:
admin@root()> bundle:find-class org.osgi.service.jpa.EntityManagerFactoryBuilder
Apache Aries JPA container (92)
org/osgi/service/jpa/EntityManagerFactoryBuilder.class
OSGi Transaction Control JPA Resource Provider - Local Transactions (290)
org/osgi/service/jpa/EntityManagerFactoryBuilder.class
OSGi Transaction Control JPA Resource Provider - XA Transactions (291)
org/osgi/service/jpa/EntityManagerFactoryBuilder.class
We’ve also had no success in tracking down a compatible version of the
defective bundle, looking at the maven repository there is a more recent
version 2.2.1, but it also has an EntityManagerFactoryBuilder that is missing
the getPersistenceProviderName():
https://mvnrepository.com/artifact/org.eclipse.persistence/javax.persistence
In summary it isn’t an option for us to configure only xa transactions or to
omit eclipselink from our karaf jvm, so any insights that help us resolve this
would be really appreciated!
Thanks
From: Jean-Baptiste Onofré <[email protected]>
Sent: Thursday, June 29, 2023 1:05 PM
To: [email protected]
Subject: Re: Autocommit is happening even within a transaction manager
Hi Ash,
What kind of datasource are you using ?
Regards
JB
On Wed, Jun 28, 2023 at 7:58 PM Ash Williams
<[email protected]<mailto:[email protected]>> wrote:
Hi,
We have an issue where sql statements executed by hibernate are being
immediately committed, despite the fact that the entity manager is managed by a
(local) transaction. It's my understanding that hibernate and the transaction
manager should together ensure that auto commit is disabled on the obtained
connection. My environment is Karaf 4.4.3 on Java 8 and hibernate 5.6.7.
# Here is the persistence.xml file:
<persistence>
<persistence-unit name="acme.pu" transaction-type="JTA" />
</persistence>
# Here is a self-contained class that demonstrates the problem:
import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.sql.DataSource;
import org.apache.commons.lang3.RandomStringUtils;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.jdbc.DataSourceFactory;
import org.osgi.service.jpa.EntityManagerFactoryBuilder;
import org.osgi.service.transaction.control.TransactionControl;
import org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory;
import org.osgi.service.transaction.control.jpa.JPAEntityManagerProvider;
import org.osgi.service.transaction.control.jpa.JPAEntityManagerProviderFactory;
@Component(immediate = true)
public class AcmeTest {
@Activate
public AcmeTest(
@Reference(target = "(osgi.unit.name<http://osgi.unit.name>=acme.pu)")
EntityManagerFactoryBuilder emfb,
@Reference(target =
"(&(osgi.jdbc.driver.name<http://osgi.jdbc.driver.name>=oracle)(osgi.jdbc.driver.class=oracle.jdbc.OracleDriver))")
DataSourceFactory dsf,
@Reference(target = "(osgi.local.enabled=true)")
JPAEntityManagerProviderFactory providerFactory,
@Reference(target = "(osgi.local.enabled=true)")
TransactionControl txControl
) throws IOException, SQLException {
// create datasource from factory
Properties dsfProps = new Properties();
dsfProps.put("user", "xxx-withheld-xxx");
dsfProps.put("password", "xxx-withheld-xxx");
dsfProps.put("url", "xxx-withheld-xxx");
DataSource datasource = dsf.createDataSource(dsfProps);
// create jpa entity manager provider from datasource and pool props
Map<String, Object> jpaProperties = new HashMap<>();
jpaProperties.put("javax.persistence.dataSource", datasource);
jpaProperties.put("hibernate.dialect",
"org.hibernate.dialect.Oracle10gDialect");
Map<String, Object> resourceProviderProperties = new HashMap<>();
resourceProviderProperties.put(JDBCConnectionProviderFactory.CONNECTION_POOLING_ENABLED,
false);
JPAEntityManagerProvider provider = providerFactory.getProviderFor(emfb,
jpaProperties, resourceProviderProperties);
// test it out by updating a test_column to a random string
EntityManager entityManager = provider.getResource(txControl);
txControl.required(() -> {
String newValue = RandomStringUtils.random(10, true, false);
Query query = entityManager.createNativeQuery("update test_table set
test_column = ? where test_name = 'test'");
query.setParameter(1, newValue);
query.executeUpdate();
// ***************************************************************
// CONNECTION HAS BEEN COMMITTED SINCE WE CAN SEE
UPDATED VALUE OF
// TEST_COLUMN IN THE DATABASE WHILST WE ARE
STILL IN THIS LAMBDA
// ***************************************************************
return null;
});
}
}
# This information about the transaction services running on the platform might
be important:
admin@root()> bundle:services -p 281
pax-transx-tm-geronimo (281) provides:
--------------------------------------
objectClass = [org.osgi.service.cm.ManagedService]
service.bundleid = 281
service.id<http://service.id> = 335
service.pid = org.ops4j.pax.transx.tm.geronimo
service.scope = singleton
----
objectClass = [javax.transaction.TransactionManager,
javax.transaction.TransactionSynchronizationRegistry,
javax.transaction.UserTransaction,
org.apache.geronimo.transaction.manager.RecoverableTransactionManage
r, org.springframework.transaction.PlatformTransactionManager]
service.bundleid = 281
service.id<http://service.id> = 360
service.scope = singleton
----
objectClass = [org.ops4j.pax.transx.tm.TransactionManager]
service.bundleid = 281
service.id<http://service.id> = 376
service.scope = singleton
admin@root()> bundle:services -p 298
OSGi Transaction Control JPA Resource Provider - Local Transactions (298)
provides:
-----------------------------------------------------------------------------------
objectClass =
[org.osgi.service.transaction.control.jpa.JPAEntityManagerProviderFactory]
osgi.local.enabled = true
service.bundleid = 298
service.id<http://service.id> = 312
service.scope = bundle
----
objectClass = [org.osgi.service.cm.ManagedServiceFactory]
service.bundleid = 298
service.id<http://service.id> = 313
service.pid = org.apache.aries.tx.control.jpa.local
service.scope = singleton
Thanks
Ash
[Image removed by sender. EDW Technology]<https://www.teamenergy.com/>
EDW Technology Ltd
3 Radian Court, Knowlhill, Milton Keynes MK5 8PJ, United Kingdom
+44 (0)844 880 2489 | www.edwt.org<https://www.edwt.org>
Energy Auditing Agency Limited (TEAM) registered in England and Wales, number
01916768. Registered office 3 Radian Court, Knowlhill, Milton Keynes MK5 8PJ.
This electronic message contains information which may be privileged or
confidential. The information is intended for the use of the individual(s) or
organisation named. If you are not the intended recipient please be aware that
any disclosure, copying, distribution or use of the contents of this
information is prohibited. If you have received this electronic message in
error, please delete this e-mail from your system and notify us by replying to
this email immediately.
________________________________
This email has been scanned for spam & viruses. If you believe this email
should have been stopped by our filters, click
here<https://portal.mailanyone.net/index.html#/outer/reportspam?token=dXNlcj1hd2lsbGlhbXNAZWR3dGVjaC5jb207dHM9MTY4ODA0MDMyMDt1dWlkPTY0OUQ3MzdCRDU0ODcyNTZDN0Q0NTU3MjY1Q0Q1Q0I3O3Rva2VuPWFlYmQ4ODEzMDk5YjljODQ3M2FiYWJjMTMzYTE2M2M2NDAwNDM1ZDM7>
to report it.
[EDW Technology]<https://www.teamenergy.com/>
EDW Technology Ltd
3 Radian Court, Knowlhill, Milton Keynes MK5 8PJ, United Kingdom
+44 (0)844 880 2489 | www.edwt.org<https://www.edwt.org>
Energy Auditing Agency Limited (TEAM) registered in England and Wales, number
01916768. Registered office 3 Radian Court, Knowlhill, Milton Keynes MK5 8PJ.
This electronic message contains information which may be privileged or
confidential. The information is intended for the use of the individual(s) or
organisation named. If you are not the intended recipient please be aware that
any disclosure, copying, distribution or use of the contents of this
information is prohibited. If you have received this electronic message in
error, please delete this e-mail from your system and notify us by replying to
this email immediately.