You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Cannot persist entities to Stardog with Empire and Spring declaritive transaction management due to StardogException: A transaction is already open exception
#113
Open
jblaufuss opened this issue
Jan 28, 2016
· 3 comments
We cannot use Empire to persist data to a Stardog instance when using Spring-managed declarative transaction management. What appears to be happening is the Empire query-execution code at com.clarkparsia.empire.impl.EntityManagerImpl.execute() method is attempting to create a transaction in addition to the one started previously by the Spring TransactionInterceptor proxy. Since Stardog does not currently support nested transactions (accourding to its documentation) this fails with an exception (attached below).
The expected behavior is that no transactions besides the one started by the TransactionInterceptor are created, and all the statements are executed within it. Our particular test case works if we remove the transaction management calls from EntityManagerImpl.execute(). A version of the same test also works if we replace the JPA impl with Hibernate and a relational database.
The src/test/java/com.thomsonreuters.empireeval.EmpireEval.testInsert() unit test in the attached demo application replicates this problem.
Empire 1.0 (code pulled from github ~1/25/2016, built from develop branch)
Stardog Community 4.0.3
Spring 4.2.2.RELEASE
Potentially problematic code:
com.clarkparsia.empire.impl.EntityManagerImpl
/**
* Execute this operation. Removes & adds all the specified data in as few database calls as possible. Then
* verifies the results of the operations
* @throws DataSourceException if there is an error while performing the add/remove operations
* @throws PersistenceException if any objects were failed to be added or removed from the database
*/
public void execute() throws DataSourceException {
// TODO: should this be in its own transaction? or join the current one?
if (getDataSource() instanceof SupportsTransactions) {
((SupportsTransactions)getDataSource()).begin();
}
try {
for (URI aGraphURI : mRemove.keySet()) {
if (doesSupportNamedGraphs() && aGraphURI != null) {
asSupportsNamedGraphs().remove(aGraphURI, mRemove.get(aGraphURI));
}
else {
getDataSource().remove(mRemove.get(aGraphURI));
}
}
for (URI aGraphURI : mAdd.keySet()) {
if (doesSupportNamedGraphs() && aGraphURI != null) {
asSupportsNamedGraphs().add(aGraphURI, mAdd.get(aGraphURI));
}
else {
getDataSource().add(mAdd.get(aGraphURI));
}
}
if (getDataSource() instanceof SupportsTransactions) {
((SupportsTransactions)getDataSource()).commit();
}
verify();
}
catch (DataSourceException e) {
if (getDataSource() instanceof SupportsTransactions) {
((SupportsTransactions)getDataSource()).rollback();
}
throw e;
}
}
Exception:
javax.persistence.PersistenceException: com.clarkparsia.empire.ds.DataSourceException: com.complexible.stardog.StardogException: A transaction is already open
at com.clarkparsia.empire.impl.EntityManagerImpl.persist(EntityManagerImpl.java:385)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:293)
at com.sun.proxy.$Proxy20.persist(Unknown Source)
at com.thomsonreuters.empireeval.dao.PersonDao.persist(PersonDao.java:31)
at com.thomsonreuters.empireeval.service.PeopleService.insertPeople(PeopleService.java:21)
at com.thomsonreuters.empireeval.service.PeopleService$$FastClassBySpringCGLIB$$dd86d87c.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
at com.thomsonreuters.empireeval.service.PeopleService$$EnhancerBySpringCGLIB$$cb2429ca.insertPeople(<generated>)
at com.thomsonreuters.empireeval.EmpireEval.testInsert(EmpireEval.java:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:254)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: com.clarkparsia.empire.ds.DataSourceException: com.complexible.stardog.StardogException: A transaction is already open
at com.complexible.stardog.empire.StardogEmpireDataSource.begin(StardogEmpireDataSource.java:226)
at com.clarkparsia.empire.impl.EntityManagerImpl$DataSourceOperation.execute(EntityManagerImpl.java:1032)
at com.clarkparsia.empire.impl.EntityManagerImpl.finishCurrentDataSourceOperation(EntityManagerImpl.java:402)
at com.clarkparsia.empire.impl.EntityManagerImpl.persist(EntityManagerImpl.java:377)
... 48 more
Caused by: com.complexible.stardog.StardogException: A transaction is already open
at com.complexible.stardog.api.impl.AbstractConnection.assertNotInTransaction(AbstractConnection.java:271)
at com.complexible.stardog.api.impl.AbstractConnection.begin(AbstractConnection.java:158)
at com.complexible.stardog.empire.StardogEmpireDataSource.begin(StardogEmpireDataSource.java:223)
... 51 more
The text was updated successfully, but these errors were encountered:
At a glance, I suspect this is related to the todo in that code, specifically, needing to be able to join a current transaction.
That's pretty straightforward to add, probably only needs to be added to SupportsTransactions. But I've never tested Empire with Spring, so there might be other issues you'll hit given that Empire isn't fully JPA-compliant.
Thanks for taking a look. We're going ahead with Empire provisionally to see how it works for us. I'll let you know if I run into any other issues using it with Spring.
If you're using Empire mostly for the Java Bean to/from RDF capabilities, or you run into other Spring JPA incompatibilities, the rendering engine of Empire was cleaned up and released separately as Pinto, and could be an option for you.
The upside would be it doesn't do anything for transactions, so you can control them yourself and get exactly the behavior you want. The downside is that it doesnt do anything for transactions so you have to control them yourself.
I'm going to move Empire to using Pinto internally (#99) which will simplify moving between just bean serialization and the more heavyweight JPA support.
We cannot use Empire to persist data to a Stardog instance when using Spring-managed declarative transaction management. What appears to be happening is the Empire query-execution code at com.clarkparsia.empire.impl.EntityManagerImpl.execute() method is attempting to create a transaction in addition to the one started previously by the Spring TransactionInterceptor proxy. Since Stardog does not currently support nested transactions (accourding to its documentation) this fails with an exception (attached below).
The expected behavior is that no transactions besides the one started by the TransactionInterceptor are created, and all the statements are executed within it. Our particular test case works if we remove the transaction management calls from EntityManagerImpl.execute(). A version of the same test also works if we replace the JPA impl with Hibernate and a relational database.
The src/test/java/com.thomsonreuters.empireeval.EmpireEval.testInsert() unit test in the attached demo application replicates this problem.
EmpireStardogTransactionBugTest.zip
Thanks for looking into this.
Versions Used:
Potentially problematic code:
com.clarkparsia.empire.impl.EntityManagerImpl
Exception:
The text was updated successfully, but these errors were encountered: