实体节点未在事务

时间:2015-08-20 10:17:35

标签: neo4j spring-data-neo4j

在外部服务器设置中使用SDN 3.3.1和Neo4j 2.1.7。

每当我执行以下执行模式时,我都有java.net.SocketTimeoutException: Read timed out

  1. 检索实体:MyEntity entity = myRepository.findByUuid(uuid);
  2. 删除该实体的关系:neo4jOperations.query("match (e{uuid:"theuuid"})<-[r:THE_RELATION]-() delete r);
  3. 更改实体的属性:entity.setTitle("New title");
  4. 保存实体:myRepository.save(entity); - &gt; 等了很长时间才得到 SocketTimeoutException
  5. 经过一些分析后,在我看来 1。在事务外的 AND 内进行http调用,正如您在此Neo4j http日志提取中所看到的那样:

    127.0.0.1 - - [20/août/2015:10:47:57 +0200] "POST /db/data/transaction HTTP/1.1" 201 659 "-" "neo4j-rest-graphdb/0" 
    127.0.0.1 - - [20/août/2015:10:47:57 +0200] "GET /db/data/node/135/relationships/in/WITH_ROLE HTTP/1.1" 200 391 "-" "neo4j-rest-graphdb/0" 
    127.0.0.1 - - [20/août/2015:10:47:57 +0200] "GET /db/data/node/149 HTTP/1.1" 200 1780 "-" "neo4j-rest-graphdb/0" 
    127.0.0.1 - - [20/août/2015:10:47:57 +0200] "GET /db/data/node/135/relationships/out/DEFAULT_ENTITY HTTP/1.1" 200 401 "-" "neo4j-rest-graphdb/0" 
    127.0.0.1 - - [20/août/2015:10:47:57 +0200] "GET /db/data/node/227 HTTP/1.1" 200 1884 "-" "neo4j-rest-graphdb/0" 
    127.0.0.1 - - [20/août/2015:10:47:57 +0200] "GET /db/data/node/135/relationships/in/WITH_PENDING_ROLE HTTP/1.1" 200 2 "-" "neo4j-rest-graphdb/0"
    

    所以我的第一个问题是:

    • 为什么像获取实体这样的操作会生成使用事务端点的查询而不会生成其他查询?

    然后, 2。中的删除操作在事务中正确完成:

    127.0.0.1 - - [20/août/2015:10:47:58 +0200] "POST /db/data/transaction/2720 HTTP/1.1" 200 254 "-" "neo4j-rest-graphdb/0" 
    

    3。显然不会生成http请求。

    最后,点 4。在被&#34;阻止后生成SocketTimeoutException&#34;一段时间(确切地说是30秒),最终生成2个http请求:

    127.0.0.1 - - [20/août/2015:10:48:28 +0200] "DELETE /db/data/transaction/2720 HTTP/1.1" 200 26 "-" "neo4j-rest-graphdb/0"
    127.0.0.1 - - [20/août/2015:10:48:28 +0200] "PUT /db/data/node/135/properties HTTP/1.1" 204 0 "-" "neo4j-rest-graphdb/0"
    

    删除是因为事务是回滚的,我认为PUT对应于save()

    在我看来,由于PUT在交易之外,因此发生了死锁! 所以,主要的问题是:

    • 为什么save()在事务之外进行PUT而不是事务内的POST?有没有办法强制使用事务端点完成实体更新?

    谢谢:)

      

    编辑:添加了SDN配置

    <beans ...>
      <tx:annotation-driven />
      <context:component-scan base-package="com.myproject.mw.neo4j.service,com.myproject.mw.neo4j.aspect" />
      <aop:aspectj-autoproxy />
      <!-- External database config -->
      <bean id="graphDatabaseServiceExternal" class="org.springframework.data.neo4j.rest.SpringCypherRestGraphDatabase"
        lazy-init="true">
          <constructor-arg index="0" value="${neo4j.path}" />
      </bean>
    
      <alias name="graphDatabaseService${neo4j.mode}" alias="graphDatabaseService" />
      <neo4j:config base-package="com.myproject.mw.neo4j.domain"
        graphDatabaseService="graphDatabaseService" />
      <neo4j:repositories base-package="com.myproject.mw.neo4j.repository" />
    </beans>
    
      

    EDIT 2 :添加实体定义和简单测试以重现

    请注意,我的Neo4j服务器位于localhost。

    测试:

    @Test
    @Transactional
    @Rollback(false)
    public void testEntityNotFound() {
        BusinessCard card = genericRepository.findByUuid("4bce6162-bc6f-bce2-bc71-bc70b63dff00");
        Entity entity = genericRepository.findByUuid("04947df8-0e9e-4471-a2f9-9af509fb5889");
        neo4jOperations.createRelationshipBetween(neo4jOperations.getNode(entity.getId()),
                neo4jOperations.getNode(card.getId()), "FAKE2", null);
        neo4jOperations.save(card);
    }
    

    BusinessCard实体:

    public class BusinessCard extends GenericNode {
        @Indexed
        private String title;
        @RelatedTo(type = RelationNames.WITH_ROLE, direction = Direction.INCOMING)
        private User user;
        @RelatedTo(type = RelationNames.WITH_PENDING_ROLE, direction = Direction.INCOMING)
        private User pendingUser;
        @RelatedTo(type = RelationNames.DEFAULT_ENTITY)
        private Entity defaultEntity;
    }
    

    实体实体:

    public class Entity extends GenericNode {
        private String logo;
        @Indexed
        private String entityName;
        @RelatedTo(type = RelationNames.IS_IN_CITY)
        private CityNode mainCity;
        @RelatedTo(type = RelationNames.IS_IN_COUNTRY)
        private CountryNode mainCountry;
        @RelatedTo(type = RelationNames.IS_IN_COUNTRIES)
        private Set<CountryNode> countries;
        @Fetch
        @RelatedToVia(type = RelationNames.TRANSLATION)
        private Set<EntityToEntityTranslatedContent> entityTranslatedContent;
        @Fetch
        @RelatedTo(type = RelationNames.HAS_KEY_STAGES)
        private KeyStage lastKeyStage;
        @GraphProperty(propertyType = Long.class)
        private Date lastProfileUpdateDateTime;
        private Integer profilCompletionIndice;
        @RelatedToVia(type = RelationNames.WORKS_AT, direction = Direction.INCOMING)
        private Set<BusinessCardWorkAt> employees = new HashSet<>();
    ...+34 more fields...
    }
    

3 个答案:

答案 0 :(得分:1)

我假设您使用的是org.springframework.data.neo4j.rest.SpringRestGraphDatabase,现已弃用,并且不支持正确的交易。 (参见生成PUT的this代码)

有一个新的基于密码的数据库org.springframework.data.neo4j.rest.SpringCypherRestGraphDatabase,它可能会做你想要的。

您还希望了解4.x版本,这是对SDN的一次改革,重点是以更有效的方式远程使用neo4j。它应该很快就会进入GA。

此博客http://jexp.de/blog/2014/12/spring-data-neo4j-improving-remoting-performance/

提供了更多解释

答案 1 :(得分:0)

然后,您的实体出现了一些问题,似乎花了很多时间将数据写入服务器。来自你的线程转储:

at org.neo4j.rest.graphdb.ExecutingRestRequest.put(ExecutingRestRequest.java:155)
at org.neo4j.rest.graphdb.RestAPIImpl.setPropertiesOnEntity(RestAPIImpl.java:633)
at org.neo4j.rest.graphdb.entity.RestEntity.flush(RestEntity.java:189)
at org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.copyPropertiesTo(SourceStateTransmitter.java:109)
at org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.write(Neo4jEntityConverterImpl.java:170)
at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister$CachedConverter.write(Neo4jEntityPersister.java:179)

和转储2:

at org.neo4j.rest.graphdb.ExecutingRestRequest.put(ExecutingRestRequest.java:155)
at org.neo4j.rest.graphdb.RestAPIImpl.setPropertiesOnEntity(RestAPIImpl.java:633)
at org.neo4j.rest.graphdb.entity.RestEntity.flush(RestEntity.java:189)
at org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.copyPropertiesTo(SourceStateTransmitter.java:109)
at org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.write(Neo4jEntityConverterImpl.java:170)
at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister$CachedConverter.write(Neo4jEntityPersister.java:179)
at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.persist(Neo4jEntityPersister.java:247)
at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.persist(Neo4jEntityPersister.java:235)
at org.springframework.data.neo4j.support.Neo4jTemplate.save(Neo4jTemplate.java:365)

还必须有其他东西,因为

org.springframework.data.neo4j.rest.SpringCypherRestGraphDatabase

应该 NOT 使用普通的Rest端点和GET,PUT,DELETE等,但只是普通的Cypher。

您还应该检查服务器的延迟和带宽,SDN3仍然非常繁琐。

因此,您应该共享实体的代码,您在调用该保存之前/之后的确切操作以及将多少数据发送到服务器。

为了获得更好的SDN + Server体验,我建议您查看为此目的从头开始编写的SDN4。 SDN4 RC2于上周五发布:

http://docs.spring.io/spring-data/neo4j/docs/4.0.0.RC2/reference/html/

答案 2 :(得分:0)

这已在SDN 3.4中修复(见https://jira.spring.io/browse/DATAGRAPH-699)。 此jira票证内容是一个不同的主题,但您可以依赖修改后的标题“单独为基于Cypher的REST-API实现缺少的操作”。 从3.4开始,使用@Transactional时不再有超出事务的REST请求。