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.