Реализация собственного репозитория для Neo4j не работает - PullRequest
0 голосов
/ 28 августа 2018

Это похоже на то, что обсуждается на Невозможно использовать два экземпляра Neo4j с загрузкой Spring / данные Spring neo4j , но у меня нет двух баз данных. Я скачал пример java-приложения spring-data neo4j из репозитория git и хочу выполнить динамический запрос вместо статического запроса через интерфейс репозитория.

У меня возникла проблема с нулевым менеджером транзакций

Вот мой интерфейс:

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), мне не нужно называть компоненты отдельно.

Я вижу следующее исключение:

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, я все равно получаю ту же ошибку последовательно.

Java-версия: 1.8

neo4j версия: 3.4.6

Чего мне не хватает?

Ответы [ 2 ]

0 голосов
/ 28 августа 2018

Геррит прав. Я хотел бы добавить два варианта, которые мы имеем здесь. Мы предоставляем инъецируемую Session, которая привязана к текущему потоку и интегрирована с транзакциями 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 и буду использовать аннотацию @Query в декларативном репозитории Spring Data Neo4j, например:

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);
    }
}

Вы найдете полное приложение в виде сущности: Используйте инъекционную сессию OGM Spring Data Neo4js . Я использовал Java 10 вместо 8, когда мы приближались к EOL для Java 8, но это не меняет реализации репозитория. Кроме того, протестировано с Spring Boot 2.0.4, Spring Data Kay и OGM 3.1.0.

Редактировать: В отношении комментария: вводимый сеанс является прокси. Само поле является окончательным, но прокси-сервер открывает сеансы по мере необходимости, а затем делегирует его.

0 голосов
/ 28 августа 2018

Вы перепутали Neo4j-OGM‘s SessionFactory / Session и поддержку @Transactional Spring (Data Neo4j). Последний создаст новую транзакцию, о которой код OGM не знает, и попытается создать новую транзакцию.

Если вы используете Spring Data Neo4j, вы также можете определить запрос в вашем хранилище сущностей с помощью аннотированного метода @Query.

Другое решение состоит в том, чтобы удалить аннотацию @Transactional на вашем сервисном уровне и создать ее вручную, если вы планируете выполнить несколько операций (не требуется для одной, потому что OGM создаст неявную транзакцию, если она не существует).

...