当前位置: 首页 > 知识库问答 >
问题:

Neo4j的自定义存储库实现不起作用

巫健柏
2023-03-14

这类似于在无法使用两个带有Spring Boot/Spring数据Neo4j的Neo4j实例中讨论的内容,但我没有两个数据库。我从git repo下载了spring data neo4j示例java应用程序,希望执行动态查询,而不是通过存储库接口执行静态查询。

我面临一个空事务管理器的问题。

这是我的界面:

public interface SearchRepositoryCustom {

    Iterable<Movie> searchByCriteria();
}

以下是我的自定义回购建议:

@Repository
@Transactional
public class SearchRepositoryImpl implements SearchRepositoryCustom {

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public Iterable<Movie> searchByCriteria() {

        String query = "MATCH (m:Movie)<-[r:ACTED_IN]-(a:Person) RETURN m,r,a LIMIT 10";
        return sessionFactory.openSession().query(Movie.class, query, Collections.emptyMap());
    }

}

以下是我的配置:

@Configuration
@EnableTransactionManagement
@EnableNeo4jRepositories(basePackages = "movies.spring.data.neo4j.repositories")
public class Neo4jPersistenceConfig {

    @Bean
    @ConfigurationProperties("spring.data.neo4j")
    public Neo4jProperties neo4jProperties() {
        return new Neo4jProperties();
    }

    @Bean
    public org.neo4j.ogm.config.Configuration userConfiguration() {
        return neo4jProperties().createConfiguration();
    }

    @Bean
    public SessionFactory getSessionFactory() {
        return new SessionFactory(userConfiguration(), "movies.spring.data.neo4j.domain");
    }

    @Bean
    public Neo4jTransactionManager transactionManager() {
        return new Neo4jTransactionManager(getSessionFactory());
    }
}

因为我只有一个TransactionManager和一个SessionFactory(因为我只有一个Neo4j实例),所以我不需要单独命名bean。

我发现以下例外情况:

org.neo4j.ogm.exception.core.TransactionManagerException: Transaction is not current for this thread
    at org.neo4j.ogm.session.transaction.DefaultTransactionManager.rollback(DefaultTransactionManager.java:86) ~[neo4j-ogm-core-3.1.0.jar:3.1.0]
    at org.neo4j.ogm.transaction.AbstractTransaction.rollback(AbstractTransaction.java:65) ~[neo4j-ogm-api-3.1.0.jar:3.1.0]
    at org.neo4j.ogm.drivers.bolt.transaction.BoltTransaction.rollback(BoltTransaction.java:61) ~[neo4j-ogm-bolt-driver-3.1.0.jar:3.1.0]
    at org.neo4j.ogm.transaction.AbstractTransaction.close(AbstractTransaction.java:144) ~[neo4j-ogm-api-3.1.0.jar:3.1.0]
    at org.springframework.data.neo4j.transaction.Neo4jTransactionManager.doCleanupAfterCompletion(Neo4jTransactionManager.java:379) ~[spring-data-neo4j-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.cleanupAfterCompletion(AbstractPlatformTransactionManager.java:1007) ~[spring-tx-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:793) ~[spring-tx-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714) ~[spring-tx-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:532) ~[spring-tx-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:304) ~[spring-tx-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at movies.spring.data.neo4j.repositories.SearchRepositoryImpl$$EnhancerBySpringCGLIB$$d2631bcd.searchByCriteria(<generated>) ~[classes/:na]
    at movies.spring.data.neo4j.controller.MovieController.advGlobal(MovieController.java:54) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_171]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_171]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]

即使我实际上继续声明bean的名称,并通过指定transactionManager的名称来标记方法transactional,我仍然会始终收到相同的错误。

Java版本:1.8

我错过了什么?

共有2个答案

别烨熠
2023-03-14

您正在混淆Neo4j-OGM的SessionFactory/会话和Spring(Data Neo4j)的@Transactional支持。后者将创建一个OGM代码不知道的新事务并尝试创建一个新事务。

如果您使用Spring Data Neo4j,您还可以使用@Query注释方法在实体存储库中定义查询。

另一种解决方案是,如果计划执行多个操作,则删除服务层中的事务注释,并手动创建它(一个操作不需要,因为如果不存在事务,OGM将创建隐式事务)。

柯镜
2023-03-14

Gerrit是对的。我想添加我们这里的两个选项。我们提供了一个可注入的会话,它绑定到当前线程并与Springs事务集成。只需自动连接它而不是SessionFactory,您就可以使用您的解决方案了。请注意,我在所有Spring项目中推荐使用构造函数注入:

@Repository
@Transactional
class SearchRepositoryImpl implements SearchRepositoryCustom {
    private final Session session;

    public SearchRepositoryImpl(Session session) {
        this.session = session;
    }

    @Override
    public Iterable<ThingEntity> searchByCriteria() {
        String query = "MATCH (t:ThingEntity)  RETURN t LIMIT 10";
        return session.query(ThingEntity.class, query, Map.of());
    }
}

我使用了另一个领域来创建一个简洁的示例项目,但想法保持不变。

对于这样一个简单的用例,我完全同意Gerrit的观点,并将在声明性Spring数据Neo4j存储库上使用Query注释,如下所示:

interface ThingRepository extends Neo4jRepository<ThingEntity, Long> {
    @Query("MATCH (t:ThingEntity)  RETURN t LIMIT 10")
    public Iterable<ThingEntity> searchByCriteria();
}

用法相同,如下所示:

@Component
class ExampleUsage implements CommandLineRunner {
    private final ThingRepository thingRepository;

    private final SearchRepositoryCustom searchRepositoryCustom;

    public ExampleUsage(ThingRepository thingRepository,  SearchRepositoryCustom searchRepositoryCustom) {
        this.thingRepository = thingRepository;
        this.searchRepositoryCustom = searchRepositoryCustom;
    }

    @Override
    public void run(String... args) {
        this.thingRepository.save(new ThingEntity(1));
        this.thingRepository.save(new ThingEntity(2));

        var things = this.searchRepositoryCustom.searchByCriteria();
        things.forEach(System.out::println);

        things = this.thingRepository.searchByCriteria();
        things.forEach(System.out::println);
    }
}

您会发现完整的应用程序作为要点:使用Spring Data Neo4js可注入的OGM会话。当我们接近EOLJava8时,我使用了Java10而不是8,但这不会改变存储库的实现。除此之外,使用Spring Boot 2.0.4、Spring Data Kay和OGM 3.1.0进行了测试

编辑:关于注释:可注入会话是一个代理。该字段本身是最终字段,但代理会根据需要打开会话,然后委托给它。

 类似资料:
  • 我使用的是Spring数据JPA1.10.11。释放 我有一个基础存储库,所有其他存储库都会扩展它。这部分有效。 我还想为一些要扩展的存储库声明一个自定义接口。所以我声明了一个接口和一个“Impl”类: 然后,我创建一个现有的工作存储库来扩展这个新接口: 注意:此存储库在扩展TestRepository之前工作,但是在如上扩展之后,应用程序上下文将无法以错误开始: 配置如下所示: 我觉得我一直在遵

  • 在我的项目中有几个实体具有相同的属性(对于示例'name'),所以,有可能创建一个存储库,其中使用自定义的select(实体)?因此,我从JpaRepository扩展了我的存储库,我扩展了MyCustomJpaRepository,MyCustomJpaRepository也扩展了JpaRepository,使其能够从JpaRepository授予基本功能? TKS

  • 项目配置为使用多个MongoTemplate Mongo Ref传递为 问题:我需要访问MongoTemplate,它是类似的标准存储库。 例如,如果正在将接口扩展为 MyRepoCustomImpl 问题:相反,难道没有任何方法可以让要使用的MongoTemplate根据它扩展到的Repo自动注入或解析吗?

  • 我正在尝试创建自己的android Asynctask实现。为此,我创建了一个抽象类,它扩展了Thread类。我为onPreExecute、onPostExecute、onProgressUpdate和doInBackground声明了方法。 我通过从主线程的循环器创建一个处理程序来运行doInBackground方法。但我无法修改onProgressUpdate()方法中的UI元素,但我可以修改

  • 我是Gradle/Groovy的新手,所以我可能遗漏了一些显而易见的东西。你能帮忙吗? 我们使用Ivy进行依赖管理。我正在试用Gradle,希望与我们现有的常春藤基础设施集成。通常情况下,这应该是可能的,但我们的常春藤的布局有点特别,而且...我不能让它工作。 这是因为我们的常春藤在布局时考虑了组织的url,例如: 我现在试着把这句话翻译成Gradle: 这当然是失败的,因为“[organizat

  • 假设我想有一个方法,它是获得超级主要客户,它有。 其中声明了方法。 然后我的公开存储库界面变成以下内容: 它扩展了和my。 我写的 bot不知道,在实现中写什么。如何接触客户?