在这篇文章之后,我正在尝试使用 @Retryable 实现我的 Invoice bean 的 save() 方法,以使我的应用程序更加可靠。我正在使用 Spring JPA + Hibernate。
我的服务有一个接口:
@RemoteDestination
@DataEnabled
@PreAuthorize("hasAnyRole('AMMINISTRATORE','CAPO_SERVIZIO','UTENTE','CONTABILITA')")
public interface FatturaCustomRepository {
@Retryable(backoff = @Backoff(delay = 200, multiplier = 2, random = true), maxAttempts = 5)
public <S extends Fattura> S save(S invoice) throws Exception;
}
这是实现:
@Override
@Transactional
public <S extends Fattura> S save(S invoice) throws Exception {
log.debug("public <S extends Fattura> S salva(S fattura, List<Long> idVendite)");
int anno = LocalDate.now().getYear();
String sQuery = "SELECT MAX(numero) FROM Fattura WHERE YEAR(data) = :anno ";
Query q = manager.createQuery(sQuery);
q.setParameter("anno", anno);
Integer maxNum = 0;
try {
maxNum = (Integer) q.getSingleResult();
log.debug("Numero trovato: " + maxNum);
if (maxNum == null)
maxNum = 0;
} catch (NoResultException e) {
maxNum = 0;
} catch (Exception e) {
maxNum = 0;
}
int numeroFattura = maxNum + 1 ;
invoice.setNumero(numeroFattura);
if (fattura.isNew())
manager.persist(invoice);
else
manager.merge(invoice);
return invoice;
}
}
模拟错误(财务编号重复)我在日志中看到 Spring 尝试重做事务,但 Hibernate 会话似乎有问题。
04/08/2015 14:13:38,475 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - public <S extends Fattura> S salva(S fattura, List<Long> idVendite)
04/08/2015 14:13:38,483 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - Anno da cercare: 2015
04/08/2015 14:13:38,497 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - Numero trovato: 4
04/08/2015 14:13:38,497 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - Fattura n. 4
04/08/2015 14:13:38,894 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - public <S extends Fattura> S salva(S fattura, List<Long> idVendite)
04/08/2015 14:13:38,895 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - Anno da cercare: 2015
04/08/2015 14:13:38,906 ERROR qtp10588730-13 FatturaCustomRepositoryImpl:102 -
04/08/2015 14:13:38,906 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - Fattura n. 0
04/08/2015 14:13:39,441 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - public <S extends Fattura> S salva(S fattura, List<Long> idVendite)
04/08/2015 14:13:39,442 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - Anno da cercare: 2015
04/08/2015 14:13:39,445 ERROR qtp10588730-13 FatturaCustomRepositoryImpl:102 -
04/08/2015 14:13:39,445 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - Fattura n. 0
04/08/2015 14:13:40,436 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - public <S extends Fattura> S salva(S fattura, List<Long> idVendite)
04/08/2015 14:13:40,437 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - Anno da cercare: 2015
04/08/2015 14:13:40,439 ERROR qtp10588730-13 FatturaCustomRepositoryImpl:102 -
04/08/2015 14:13:40,440 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - Fattura n. 0
04/08/2015 14:13:42,686 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - public <S extends Fattura> S salva(S fattura, List<Long> idVendite)
04/08/2015 14:13:42,687 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - Anno da cercare: 2015
04/08/2015 14:13:42,689 ERROR qtp10588730-13 FatturaCustomRepositoryImpl:102 -
04/08/2015 14:13:42,690 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - Fattura n. 0
04/08/2015 14:13:42,691 ERROR qtp10588730-13 TestServiceImpl:114 -
java.lang.IllegalStateException: There are delayed insert actions before operation as cascade level 0.
at org.hibernate.internal.SessionImpl.checkNoUnresolvedActionsBeforeOperation(SessionImpl.java:652) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:809) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1181) ~[hibernate-entitymanager-4.3.10.Final.jar:4.3.10.Final]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_45]
at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_45]
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:291) ~[spring-orm-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at com.sun.proxy.$Proxy243.persist(Unknown Source) ~[?:?]
at it.pianetatecno.aci.servicesimpl.FatturaCustomRepositoryImpl.salva(FatturaCustomRepositoryImpl.java:116) ~[aci-java-1.7.6.jar:1.7.6]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_45]
at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_45]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:68) ~[spring-security-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.retry.interceptor.RetryOperationsInterceptor$1.doWithRetry(RetryOperationsInterceptor.java:74) ~[spring-retry-1.1.2.RELEASE.jar:?]
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:263) ~[spring-retry-1.1.2.RELEASE.jar:?]
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:154) ~[spring-retry-1.1.2.RELEASE.jar:?]
at org.springframework.retry.interceptor.RetryOperationsInterceptor.invoke(RetryOperationsInterceptor.java:101) ~[spring-retry-1.1.2.RELEASE.jar:?]
at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:118) ~[spring-retry-1.1.2.RELEASE.jar:?]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281) ~[spring-tx-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at com.sun.proxy.$Proxy254.salva(Unknown Source) ~[?:?]
at it.pianetatecno.aci.servicesimpl.TestServiceImpl.inserimentoVendita(TestServiceImpl.java:112) [aci-java-1.7.6.jar:1.7.6]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_45]
at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_45]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) [spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) [spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) [spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:68) [spring-security-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) [spring-tx-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281) [spring-tx-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) [spring-tx-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) [spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at com.sun.proxy.$Proxy273.inserimentoVendita(Unknown Source) [?:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_45]
at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_45]
at org.granite.messaging.service.ServiceInvocationContext.invoke(ServiceInvocationContext.java:72) [granite-server-core-3.1.2-SNAPSHOT.jar:?]
at org.granite.messaging.service.security.AbstractSecurityService.endAuthorization(AbstractSecurityService.java:108) [granite-server-core-3.1.2-SNAPSHOT.jar:?]
at org.granite.spring.security.SpringSecurity3Service.authorize(SpringSecurity3Service.java:292) [granite-server-spring-3.1.2-SNAPSHOT.jar:?]
at org.granite.messaging.service.ServiceInvoker.invoke(ServiceInvoker.java:220) [granite-server-core-3.1.2-SNAPSHOT.jar:?]
at org.granite.messaging.amf.process.AMF3MessageProcessor.processRemotingMessage(AMF3MessageProcessor.java:141) [granite-server-core-3.1.2-SNAPSHOT.jar:?]
at org.granite.messaging.amf.process.AMF3MessageProcessor.process(AMF3MessageProcessor.java:60) [granite-server-core-3.1.2-SNAPSHOT.jar:?]
at org.granite.messaging.amf.process.AMF0MessageProcessor.process(AMF0MessageProcessor.java:79) [granite-server-core-3.1.2-SNAPSHOT.jar:?]
at org.granite.messaging.webapp.AMFEndpoint.serviceJMFAMF(AMFEndpoint.java:151) [granite-server-core-3.1.2-SNAPSHOT.jar:?]
at org.granite.messaging.webapp.AMFEndpoint.service(AMFEndpoint.java:64) [granite-server-core-3.1.2-SNAPSHOT.jar:?]
at org.granite.spring.ServerFilter.handle(ServerFilter.java:331) [granite-server-spring-3.1.2-SNAPSHOT.jar:?]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959) [spring-webmvc-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893) [spring-webmvc-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966) [spring-webmvc-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868) [spring-webmvc-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707) [javax.servlet-api-3.1.0.jar:3.1.0]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842) [spring-webmvc-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) [javax.servlet-api-3.1.0.jar:3.1.0]
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:806) [jetty-servlet-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669) [jetty-servlet-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:224) [websocket-server-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) [jetty-servlet-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585) [jetty-servlet-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) [jetty-server-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:550) [jetty-security-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223) [jetty-server-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1128) [jetty-server-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515) [jetty-servlet-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185) [jetty-server-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1062) [jetty-server-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) [jetty-server-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215) [jetty-server-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:110) [jetty-server-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:113) [jetty-server-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.server.Server.handle(Server.java:507) [jetty-server-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:284) [jetty-server-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:237) [jetty-server-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:240) [jetty-io-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:93) [jetty-io-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:53) [jetty-io-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceRun.produceAndRun(ExecuteProduceRun.java:191) [jetty-util-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceRun.run(ExecuteProduceRun.java:126) [jetty-util-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:641) [jetty-util-9.3.0.M2.jar:9.3.0.M2]
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:559) [jetty-util-9.3.0.M2.jar:9.3.0.M2]
at java.lang.Thread.run(Thread.java:745) [?:1.8.0_45]
这个奇怪的错误出现在控制台中:
04/08/2015 14:13:40,437 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - Anno da cercare: 2015
ago 04, 2015 2:13:40 PM org.hibernate.AssertionFailure <init>
ERROR: HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: null id in it.pianetatecno.aci.domain.fatture.Fattura entry (don't flush the Session after an exception occurs)
04/08/2015 14:13:40,439 ERROR qtp10588730-13 FatturaCustomRepositoryImpl:102 -
04/08/2015 14:13:40,440 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - Fattura n. 0
04/08/2015 14:13:42,686 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - public <S extends Fattura> S salva(S fattura, List<Long> idVendite)
04/08/2015 14:13:42,687 DEBUG qtp10588730-13 FatturaCustomRepositoryImpl:90 - Anno da cercare: 2015
ago 04, 2015 2:13:42 PM org.hibernate.AssertionFailure <init>
ERROR: HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: null id in it.pianetatecno.aci.domain.fatture.Fattura entry (don't flush the Session after an exception occurs)
Spring重试不应该对应用程序的其余部分透明吗?代码中的问题在哪里?
谢谢