Java 诊断Spring数据中的事务异常

Java 诊断Spring数据中的事务异常,java,spring,spring-data,spring-data-neo4j,Java,Spring,Spring Data,Spring Data Neo4j,在使用Spring数据Neo4j(使用简单映射模式)时,我偶尔会遇到NotInTransactionException被抛出到用@Transactional注释的方法中,我发现自己在诊断这些异常时拔出的头发比我能承受的要多。例如,以下方法: @Service public class FooService { @Autowired Neo4jTemplate template; //GraphPersisted is an interface containing a single

在使用Spring数据Neo4j(使用简单映射模式)时,我偶尔会遇到
NotInTransactionException
被抛出到用
@Transactional
注释的方法中,我发现自己在诊断这些异常时拔出的头发比我能承受的要多。例如,以下方法:

@Service 
public class FooService { 
  @Autowired Neo4jTemplate template;

  //GraphPersisted is an interface containing a single method: Long getId()
  //ModelNode is an empty interface implemented by my @NodeEntity classes 

  @Transactional
  public <T extends ModelNode> T getNode(GraphPersisted g, Class<T> clazz){          
    return template.repositoryFor(clazz).findOne(g.getId()); //NotInTransactionException!!
  }
}
@服务
公共类服务{
@自动连线Neo4jTemplate模板;
//GraphPersisted是一个包含单个方法的接口:Long getId()
//ModelNode是由@NodeEntity类实现的空接口
@交易的
公共T getNode(GraphPersisted g,类clazz){
返回template.repositoryFor(clazz).findOne(g.getId());//NotInTransactionException!!
}
}
以下是:

Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: nested exception is org.neo4j.graphdb.NotInTransactionException
at org.springframework.data.neo4j.support.Neo4jExceptionTranslator.translateExceptionIfPossible(Neo4jExceptionTranslator.java:51)
at org.springframework.data.neo4j.support.Neo4jTemplate.translateExceptionIfPossible(Neo4jTemplate.java:447)
at org.springframework.data.neo4j.support.Neo4jTemplate.getNode(Neo4jTemplate.java:481)
at org.springframework.data.neo4j.repository.NodeGraphRepositoryImpl.getById(NodeGraphRepositoryImpl.java:33)
at org.springframework.data.neo4j.repository.NodeGraphRepositoryImpl.getById(NodeGraphRepositoryImpl.java:24)
at org.springframework.data.neo4j.repository.AbstractGraphRepository.findOne(AbstractGraphRepository.java:127)
at org.springframework.data.neo4j.repository.AbstractGraphRepository.findOne(AbstractGraphRepository.java:51)
at net.mypkg.myapp.core.FooService.getNode(FooService.java:28)
at net.mypkg.myapp.citizenry.BarService.getCitNode(BarService.java:136)
at net.mypkg.myapp.citizenry.BarService.loadCitizens(BarService.java:81)
at net.mypkg.myapp.citizenry.BarService$$FastClassBySpringCGLIB$$792b7a4e.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:640)
at net.mypkg.myapp.citizenry.BarService$$EnhancerBySpringCGLIB$$59949515.loadCitizens(<generated>)
at net.mypkg.myapp.creator.builders.VotingActivityBuilder.makeVotesFor(VotingActivityBuilder.java:46)
at net.mypkg.myapp.creator.builders.VotingActivityBuilder.build(VotingActivityBuilder.java:35)
at net.mypkg.myapp.creator.builders.VotingActivityBuilder$$FastClassBySpringCGLIB$$6871225a.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:640)
at net.mypkg.myapp.creator.builders.VotingActivityBuilder$$EnhancerBySpringCGLIB$$7f5827a1.build(<generated>)
at net.mypkg.myapp.creator.Creator.create(Creator.java:33)
at net.mypkg.myapp.creator.CreatorDriver.run(CreatorDriver.java:52)
at org.springframework.boot.SpringApplication.runCommandLineRunners(SpringApplication.java:634)
... 5 more
原因:org.springframework.dao.InvalidDataAccessApiUsageException:嵌套异常为org.neo4j.graphdb.NotInTransactionException
位于org.springframework.data.neo4j.support.Neo4jExceptionTranslator.translateExceptionIffailable(Neo4jExceptionTranslator.java:51)
在org.springframework.data.neo4j.support.Neo4jTemplate.translateExceptionIfmable(Neo4jTemplate.java:447)上
位于org.springframework.data.neo4j.support.Neo4jTemplate.getNode(Neo4jTemplate.java:481)
位于org.springframework.data.neo4j.repository.NodeGraphRepositoryImpl.getById(NodeGraphRepositoryImpl.java:33)
位于org.springframework.data.neo4j.repository.NodeGraphRepositoryImpl.getById(NodeGraphRepositoryImpl.java:24)
位于org.springframework.data.neo4j.repository.AbstractGraphRespository.findOne(AbstractGraphRespository.java:127)
位于org.springframework.data.neo4j.repository.AbstractGraphRespository.findOne(AbstractGraphRespository.java:51)
位于net.mypkg.myapp.core.FooService.getNode(FooService.java:28)
位于net.mypkg.myapp.citizenry.BarService.getCitNode(BarService.java:136)
位于net.mypkg.myapp.citizenry.BarService.loadCitizens(BarService.java:81)
在net.mypkg.myapp.citizenry.BarService$$FastClassBySpringCGLIB$$792b7a4e.invoke()上
位于org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
位于org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:640)
在net.mypkg.myapp.citizenry.BarService$$EnhancerBySpringCGLIB$$59949515.loadCitizens()上
在net.mypkg.myapp.creator.builders.VotingActivityBuilder.makeVotesFor(VotingActivityBuilder.java:46)
位于net.mypkg.myapp.creator.builders.VotingActivityBuilder.build(VotingActivityBuilder.java:35)
在net.mypkg.myapp.creator.builders.VotingActivityBuilder$$FastClassBySpringCGLIB$$6871225a.invoke()上
位于org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
位于org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:640)
在net.mypkg.myapp.creator.builders.VotingActivityBuilder$$EnhancerBySpringCGLIB$$7f5827a1.build()上
位于net.mypkg.myapp.creator.creator.create(creator.java:33)
net.mypkg.myapp.creator.CreatorDriver.run(CreatorDriver.java:52)
位于org.springframework.boot.SpringApplication.runCommandLineRunners(SpringApplication.java:634)
... 还有5个
我最直接的问题是:为什么会抛出此异常?为什么我的
@Transactional
注释没有执行我期望它执行的操作(即在事务中包装对
template.findOne(Long id)
的调用)

我更大的问题是:您如何知道?堆栈跟踪中给出了哪些线索,可能表明意外行为是从何处产生的?我对Spring和Spring数据比较陌生,我确信这些问题在本质上并不难诊断,我只是在努力这样做,因为我不知道如何解释堆栈跟踪:当出现这些问题时,我应该在跟踪中寻找什么来诊断这些问题


(请让我知道回答这个问题需要什么进一步的代码/配置,我会发布它-我故意尽可能少地包含,希望您需要看到的诊断这个特定问题的内容将帮助我了解我需要看什么来诊断未来类似的异常。不过,我会说,
@Transactional
注释在同一应用程序上下文中的大量其他方法中正常工作)

从stacktrace判断,
BarService
的一个实例正在调用
FooService
的一个非代理实例。如果后者是代理,您将在stacktrace中看到
CGLibEnhance
-ed类和-IIRC-在您的例子中,还有负责启动交易


至于为什么实例没有被代理,这很难说。是否缺少
@EnableTransactionManagement
实例?实例是否不是由Spring管理的?类是否不能被代理,因为它是最终版本?

在回答中总结一些想法:Spring(任何最新版本)通过实例化包含带“@Transactional”注释的方法的对象的代理来建立事务。这些代理(使用处理事务的输入/退出代码包装原始功能)通过以下两种方式之一生成:

1) 通过CGLIB动态生成代理目标子类的Java字节码,覆盖带注释的方法,使用该子类的实例加上原始类的实例

2) 通过Java动态代理,通过使用原始类的实例动态生成实现代理目标的所有接口的对象,模拟目标类

除非另有明确说明,否则Spring会尝试使用2)。如果目标类未实现任何接口,则As 2)不起作用。必须选择选项1)。回到选项1)也可能会失败。考虑最终方法(如Maarten所述)或比
public
范围更严格的方法

这些一般的事情
java.lang.IllegalArgumentException: This is for testing purposes.
  at eu.example.service.FooService.getNode(FooService.java:94)
  at eu.example.service.FooService$$FastClassByCGLIB$$837ba2c0.invoke(<generated>)
  at o.s.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
  at o.s.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698)
  at o.s.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
  at o.s.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
  at o.s.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
  at o.s.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
  at o.s.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
  at o.s.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
  at eu.example.service.FooService$$EnhancerByCGLIB$$e1fb8939.getNode(<generated>)