3

Im building a REST service with Jersey, running on Payara. The service uses Spring Data (and JPA/JTA below that) to access the database.

I noticed that after a server restart, the first call to the service worked but the result was never written to the database. by that i mean that i receive a JSON response from the service with the correct results and neither on the client nor the server side are any exceptions visible. but the JSON result that is also persisted to the database never shows up in the database.

the second call and all that follow after that, work fine and commit their results to the database.

through extended JTA logging i found out that the first call after a server restart always rollsback it's transaction at the end of the service. thats why the results don't show up in the database. starting with the second call the transaction is committed.

I was able to pinpoint the Spring Data repositories as the culprit for this.

if, after a server restart, the first call to a Spring Data repository is inside a JTA transaction (inside a method annotated with @Transactional). That call will fail and rollback the transaction.

if the same thing happens but outside a JTA transaction that first call will be fine and after that you can use the repositores inside or outside JTA transaction without any problems.

but it seems there is some sort of "initialization" that needs to take place outside of a transaction context for the repositories to work.

I managed to "dumb down" the problem into a small demo service to demonstrate it easier and in that dumbed down version i can actually see the exception that is thrown (no idea as of yet why i don't see that exception in my real service).

have a look at these two REST services:

@Inject
private TestBP testBP;

@GET
@Consumes(MediaType.TEXT_PLAIN + ";charset=utf-8")
@Path("init")
public String init(@QueryParam("company") String companyName) {
    Company company = testBP.findCompany(companyName);
    return company.toString();
}

@GET
@Consumes(MediaType.TEXT_PLAIN + ";charset=utf-8")
@Path("initWithTA")
public String initWithTA(@QueryParam("company") String companyName) {
    Company company = testBP.findCompanyInTransaction(companyName);
    return company.toString();
}

and the simple business process "TestBP" that goes along with them:

@Inject private CompanyRepository companyRepository;

public Company findCompany(String companyName) {
    return companyRepository.findByName(companyName);
}

@Transactional
public Company findCompanyInTransaction(String companyName) {
    return companyRepository.findByName(companyName);
}

The only difference between the two services is the "@Transactional" annotation on the "findCompanyInTransaction" method.

if you deploy this and call the initWithTA() method as the first service after the server restart, you will get an exception:

2017-10-09T11:36:29.981+0200|Warnung: StandardWrapperValve[de.myCompany.cccs.customerscoring.webservice.RestConfig]: Servlet.service() for servlet de.myCompany.cccs.customerscoring.webservice.RestConfig threw exception
javax.transaction.RollbackException
    at com.sun.jts.jta.TransactionImpl.registerSynchronization(TransactionImpl.java:305)
    at com.sun.enterprise.transaction.JavaEETransactionImpl.registerSynchronization(JavaEETransactionImpl.java:694)
    at org.eclipse.persistence.internal.jpa.transaction.JTATransactionWrapper.registerIfRequired(JTATransactionWrapper.java:136)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.setJTATransactionWrapper(EntityManagerImpl.java:2164)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.detectTransactionWrapper(EntityManagerImpl.java:889)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.initialize(EntityManagerImpl.java:412)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.<init>(EntityManagerImpl.java:405)
    at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.createEntityManagerImpl(EntityManagerFactoryDelegate.java:322)
    at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:337)
    at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:303)
    at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:85)
    at org.springframework.data.jpa.repository.query.SimpleJpaQuery.<init>(SimpleJpaQuery.java:62)
    at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromMethodWithQueryString(JpaQueryFactory.java:72)
    at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromQueryAnnotation(JpaQueryFactory.java:53)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:144)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:212)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:77)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:436)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:221)
    at org.springframework.data.jpa.repository.cdi.JpaRepositoryBean.create(JpaRepositoryBean.java:73)
    at org.springframework.data.repository.cdi.CdiRepositoryBean.create(CdiRepositoryBean.java:374)
    at org.springframework.data.repository.cdi.CdiRepositoryBean.create(CdiRepositoryBean.java:172)
    at org.jboss.weld.context.AbstractContext.get(AbstractContext.java:96)
    at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.get(ContextualInstanceStrategy.java:100)
    at org.jboss.weld.bean.ContextualInstance.get(ContextualInstance.java:50)
    at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:99)
    at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:99)
    at de.myCompany.cccs.customerscoring.entities.repos.CompanyRepository$CrudRepository$1639644976$Proxy$_$$_WeldClientProxy.findByName(Unknown Source)
    at de.myCompany.cccs.customerscoring.bp.TestBP.findCompanyInTransaction(TestBP.java:77)
    at de.myCompany.cccs.customerscoring.bp.TestBP$Proxy$_$$_WeldSubclass.findCompanyInTransaction$$super(Unknown Source)
    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:498)
    at org.jboss.weld.interceptor.proxy.TerminalAroundInvokeInvocationContext.proceedInternal(TerminalAroundInvokeInvocationContext.java:49)
    at org.jboss.weld.interceptor.proxy.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:77)
    at org.glassfish.jersey.ext.cdi1x.transaction.internal.WebAppExceptionInterceptor.intercept(WebAppExceptionInterceptor.java:77)
    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:498)
    at org.jboss.weld.interceptor.reader.SimpleInterceptorInvocation$SimpleMethodInvocation.invoke(SimpleInterceptorInvocation.java:73)
    at org.jboss.weld.interceptor.proxy.NonTerminalAroundInvokeInvocationContext.proceedInternal(NonTerminalAroundInvokeInvocationContext.java:64)
    at org.jboss.weld.interceptor.proxy.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:77)
    at org.glassfish.cdi.transaction.TransactionalInterceptorBase.proceed(TransactionalInterceptorBase.java:228)
    at org.glassfish.cdi.transaction.TransactionalInterceptorRequired.transactional(TransactionalInterceptorRequired.java:103)
    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:498)
    at org.jboss.weld.interceptor.reader.SimpleInterceptorInvocation$SimpleMethodInvocation.invoke(SimpleInterceptorInvocation.java:73)
    at org.jboss.weld.interceptor.proxy.InterceptorMethodHandler.executeAroundInvoke(InterceptorMethodHandler.java:84)
    at org.jboss.weld.interceptor.proxy.InterceptorMethodHandler.executeInterception(InterceptorMethodHandler.java:72)
    at org.jboss.weld.interceptor.proxy.InterceptorMethodHandler.invoke(InterceptorMethodHandler.java:56)
    at org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler.invoke(CombinedInterceptorAndDecoratorStackMethodHandler.java:79)
    at org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler.invoke(CombinedInterceptorAndDecoratorStackMethodHandler.java:68)
    at de.myCompany.cccs.customerscoring.bp.TestBP$Proxy$_$$_WeldSubclass.findCompanyInTransaction(Unknown Source)
    at de.myCompany.cccs.customerscoring.bp.TestBP$Proxy$_$$_WeldClientProxy.findCompanyInTransaction(Unknown Source)
    at de.myCompany.cccs.customerscoring.webservice.Scoring.initWithTA(Scoring.java:135)
    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:498)
    at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:205)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
    at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
    at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1606)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:258)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:654)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:593)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:371)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:238)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:466)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:169)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:539)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:593)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:573)
    at java.lang.Thread.run(Thread.java:748)

But if you call the init() method first (the one without a transaction context) it will work. after that first call to init() you can also call the initWithTA() method and it will work, too.

does anyone have any ideas to what root cause this may be related to?

since i assume that this may have something to do with the configuration of Spring and the transaction manager i will provide my applicationContext.xml for reference here:

<jpa:repositories base-package="de.myCompany.cccs.customerscoring.entities" />
<context:component-scan base-package="de.myCompany.cccs" />
<tx:jta-transaction-manager />
<tx:annotation-driven />

thanks in advance for any ideas!

regards, Mario.

Tobi Tiggers
  • 442
  • 3
  • 14
Mario Köhler
  • 192
  • 1
  • 10
  • What is the package name of Transactional class? – yılmaz Oct 09 '17 at 10:17
  • it's javax.transaction.Transactional – Mario Köhler Oct 09 '17 at 15:03
  • can you try org.springframework.transaction.annotation.transactional? – yılmaz Oct 09 '17 at 15:21
  • using the Spring `@Transactional` avoids the exception during the first call, BUT as soon as you try to call e.g. save() on the repo, you will get a javax.persistence.TransactionRequiredException. Which makes sense., since i used the spring `@Transactional` there isn't a JTA transaction during the first call, so it's basically like calling the other method that has no @Transactional annotation, thats why it's working and doesn't throw the exception anymore... – Mario Köhler Oct 10 '17 at 05:00
  • ...and the finder (read) method works without a JTA transaction, because read operations are not dependent on a transaction. but as soon as you do something with the repository that requires a transaction (like save() ) you seem to need a JTA (javax.transaction) transaction and not a Spring transaction. Which also makes sense to me, because i configured it to use the jta transaction management (see applicationContext.xml). So i don't believe this is the right approach. – Mario Köhler Oct 10 '17 at 05:00

0 Answers0