1. 程式人生 > >spring data neo4j 查詢超時問題

spring data neo4j 查詢超時問題

使用sdn查詢時,當資料量較大並且需要做全庫掃描時,很容易出現超時問題。丟擲如下異常:

Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: java.net.SocketTimeoutException: Read timed out
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:149)
    at org.neo
4j.rest.graphdb.UserAgent$1.handle(UserAgent.java:68) at com.sun.jersey.api.client.filter.HTTPBasicAuthFilter.handle(HTTPBasicAuthFilter.java:81) at com.sun.jersey.api.client.Client.handle(Client.java:648) at com.sun.jersey.api.client.WebResource.handle(WebResource.java:670) at com.sun
.jersey.api.client.WebResource.access$200(WebResource.java:74) at com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:553) at org.neo4j.rest.graphdb.ExecutingRestRequest.post(ExecutingRestRequest.java:145) at org.neo4j.rest.graphdb.RestAPIImpl.query(RestAPIImpl.java:486)

於是考慮加入超時時間,形式如:

System.setProperty("org.neo4j.rest.read_timeout", "80");

但是此時,查詢sql呼叫的形式是,Repository+註解,該System的屬性設定對於Spring託管的client並沒有生效,此時查詢仍然會出現超時問題,接下來會對該問題從原始碼上做分析。如果此時設定超時時間後,新new出一個client,這是超時時間設定就生效了,具體程式碼如:

System.setProperty("org.neo4j.rest.read_timeout", "80");
RestAPI restAPIFacade1 = buildClient(address1, userName1, password1);
CypherResult cr = restAPIFacade1.query("xxx", new HashMap<String, Object>());
System.out.println("cost time: " + (System.currentTimeMillis() - ss));
System.out.println(cr.asMap().get("data"));

為何這樣設定就會生效,我們可以跟進看一下原始碼:
RestAPI restAPIFacade1 = buildClient(address1, userName1, password1) 其實呼叫的是:
restAPIFacade = new RestAPIImpl(address, userName, password);
接下來:

public RestAPIImpl(String uri, String user, String password) {
        this.entityRefetchTimeInMillis = TimeUnit.SECONDS.toMillis(1000L);
        this.entityCache = new RestEntityCache(this);
        this.restEntityExtractor = new RestEntityExtractor(this);
        this.restRequest = this.createRestRequest(uri, user, password);
        this.restIndexAPI = new RestAPIIndexImpl(this);
    }

繼續到 this.createRestRequest(uri, user, password):

protected RestRequest createRestRequest(String uri, String user, String password) {
        return new ExecutingRestRequest(uri, user, password);
    }

繼續:

public ExecutingRestRequest(String baseUri, String username, String password) {
        this.userAgent = new UserAgent();
        this.baseUri = this.uriWithoutSlash(baseUri);
        this.client = this.createClient();
        this.addAuthFilter(username, password);
    }

繼續createClient內部為:

protected Client createClient() {
        Client client = Client.create();
        client.setConnectTimeout(Integer.valueOf(Config.getConnectTimeout()));
        client.setReadTimeout(Integer.valueOf(Config.getReadTimeout()));
        client.setChunkedEncodingSize(Integer.valueOf(8192));
        this.userAgent.install(client);
        if(Config.useLoggingFilter()) {
            client.addFilter(new LoggingFilter());
        }

        return client;
    }

我們注意到,此時client在構造過程中,會有 設定timeout的步驟,繼續檢視Config.getReadTimeout(),整個Config類不長,貼上全部程式碼:

package org.neo4j.rest.graphdb.util;

import java.util.concurrent.TimeUnit;

public class Config {
    public static final String CONFIG_PREFIX = "org.neo4j.rest.";
    public static final String CONFIG_STREAM = "org.neo4j.rest.stream";
    public static final String CONFIG_BATCH_TRANSACTION = "org.neo4j.rest.batch_transaction";
    public static final String CONFIG_LOG_REQUESTS = "org.neo4j.rest.logging_filter";
    public static final String WRITE_THREADS = "write_threads";

    public Config() {
    }

    public static int getConnectTimeout() {
        return getTimeout("connect_timeout", 30);
    }

    public static int getReadTimeout() {
        return getTimeout("read_timeout", 30);
    }

    public static boolean streamingIsEnabled() {
        return Boolean.parseBoolean(System.getProperty("org.neo4j.rest.stream", "true"));
    }

    public static boolean useBatchTransactions() {
        return System.getProperty("org.neo4j.rest.batch_transaction", "false").equalsIgnoreCase("true");
    }

    public static boolean useLoggingFilter() {
        return System.getProperty("org.neo4j.rest.logging_filter", "false").equalsIgnoreCase("true");
    }

    private static int getTimeout(String param, int defaultValue) {
        return (int)TimeUnit.SECONDS.toMillis((long)Integer.parseInt(System.getProperty("org.neo4j.rest." + param, "" + defaultValue)));
    }

    public static int getWriterThreads() {
        return Integer.parseInt(System.getProperty("org.neo4j.rest.write_threads", "10"));
    }
}

很簡單,在這裡我們看到client生成時,超時時間設定的整個過程,在未設定系統引數時,超時時間取的預設值30s(從程式碼中也可觀察到為什麼我們設定執行環境變數的key為 org.neo4j.rest.read_timeout)。那麼接下來我們如何設定超時時間呢?這個也很簡單,jvm可選引數中做如下設定:

-Dorg.neo4j.rest.read_timeout=150

通常該引數在idea或eclipse中的VM options中。
在有些情況下,我們可能需要直接在tomcat中設定,比如在beta或者生產環境的伺服器上。我們可以tomcat的啟動引數指令碼中設定,通常在tomcat/bin下的catalina.cmd,或catalina.sh,以及startenv.sh等指令碼中設定即可。
如果有多臺伺服器,並且可能部署在虛擬容器上,此時如果生成環境時,就需要額外在tomcat上做上述設定,也是相當的繁瑣的。我們上面遇到的問題是,通過spring容器生成的neo4j client 超時時間設定不生效。其實問題在於spring生成例項時,該系統屬性並未設定。所以,可以藉助spring提供的工具來完成環境引數的設定。
在springContext.xml中做如下配置:

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetClass" value="java.lang.System" />
        <property name="targetMethod" value="setProperty" />
        <property name="arguments">
            <list>
                <value>org.neo4j.rest.read_timeout</value>
                <value>${neo4j.read.timeout}</value>
            </list>
        </property>
    </bean>

注意,根據spring bean的生成順序,該bean必須在新增在neo4j client 的bean 配置之前方能生效。該方法是較為優雅的解決方法了。
另外關於org.springframework.beans.factory.config.MethodInvokingFactoryBean 的使用,可以另外再做整理和總結了。

相關推薦

spring data neo4j 查詢超時問題

使用sdn查詢時,當資料量較大並且需要做全庫掃描時,很容易出現超時問題。丟擲如下異常: Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: java.ne

訪問Neo4j spring-data-neo4j入門 (二)@Query 複雜查詢

本文在訪問Neo4j spring-data-neo4j入門 (一) 基礎上成文,因此請先閱讀訪問Neo4j spring-data-neo4j入門 (一) 。 我們在上一篇提到使用@Query完成複雜查詢,如同我們的業務一樣,使用簡單的比較大小、日期範圍無法完成業務需要,特別是當我

spring data jpa 查詢自定義欄位,轉換為自定義實體

目標:查詢資料庫中的欄位,然後轉換成 JSON 格式的資料,返回前臺。 環境:idea 2016.3.4, jdk 1.8, mysql 5.6, spring-boot 1.5.2 背景:首先建立 entity 對映資料庫(非專業 java 不知道這怎麼說) @Entity @Tab

Spring系列學習之Spring Data Neo4J資料訪問

英文原文:https://spring.io/projects/spring-data-neo4j 目錄 概述 特性 學習 文件 概述 該專案為Neo4j圖形資料庫提供Spring Data支援,包括帶註釋的POJO,SD-Repositories和Neo4j-Tem

QQA: Spring Data 如何查詢屬性是否在列表中

每篇文章有多個標籤,選中多個標籤,要求找出含有該標籤的文章。同時如果選中標籤為空,則返回所有文章。Spring Data/JPA 如何實現? 可以使用 Spring Data Specification 動態建立查詢語句,最終結果如下: public interface PostRepository exte

使用Spring訪問Mongodb的方法大全——Spring Data MongoDB查詢指南

1.概述 Spring Data MongoDB 是Spring框架訪問mongodb的神器,藉助它可以非常方便的讀寫mongo庫。本文介紹使用Spring Data MongoDB來訪問mongodb資料庫的幾種方法: 使用Query和Criteria類 JPA自動生成的查詢方法

Spring Data Neo4j reference文件中關於@RelatedTo註解的注意事項

源於3.2.2的reference文件 22.5.5.基於結束節點(end node)區分關係 22.5.5. Discriminating Relationships Based On End Node Type ... Example 61. Discrimin

利用Spring Data Neo4j搭建推薦系統

本文作者Daniel Bartl是一位專案開發者,在這裡分享如何使用Spring Data Neo4j來構建推薦系統。Neo4j是一款非常流行的開源圖型NoSQL資料庫。它完全支援ACID資料庫事務屬性,由於其良好的圖形資料模型設計,Neo4j的速度非常快。對於連線的資料操作,Neo4j的速度要比傳統的關

通過Spring Data Neo4J操作您的圖形資料庫

在前面的一篇文章《圖形資料庫Neo4J簡介》中,我們已經對其內部所使用的各種機制進行了簡單地介紹。而在我們嘗試對Neo4J進行大版本升級時,我發現網路上並沒有任何成型的樣例程式碼以及簡介,而其自身的文件也對如何使用Spring Data Neo4J介紹得語焉不詳。因此在本文

Spring Data JPA查詢關鍵字

        Spring Data JPA使用方法名可解決大部分的查詢問題,但是也存在不能解決所有問題,以下是方法名中支援的關鍵字: 關鍵字 示例 JPQL 片段 And findByL

Spring Data Neo4j個人筆記

由於機緣巧合,原來要接手做一個和圖資料庫相關的外包專案。但是由於臨近畢業,各種壓力大,遂放棄。但是自己還是各種翻牆瞭解了一番Neo4j,我自己理解的Neo4j就是一個圖資料庫,它存在的目的就是類似一個引擎,使得一些巢狀級別高的,可以以更快的速度來獲取結果。僅僅是個人見解,不知道對不對。發現度娘很難找到自己需

Spring Data JPA 實例查詢

customer 數據庫表 查詢方式 記錄 如何 三、認識“實例查詢” 1、概念定義: 上面例子中,是這樣創建“實例”的:Example<Customer> ex = Example.of(customer, matcher);我們看到,Example對象,由custom

SpringBoot中使用Spring Data Jpa 實現簡單的動態查詢的兩種方法

ppr eat value table 得到 blog .net ride integer 首先謝謝大佬的簡書文章:http://www.jianshu.com/p/45ad65690e33# 這篇文章中講的是spring中使用spring data jpa,使用了xml配

Spring Data JPA動態查詢(多條件and)

ica cat 滿足 from pos true ans let tid entity: @Entity @Table(name = "data_illustration") public class Test { @Id @Gen

Spring Data JPA 多個實體類表聯合視圖查詢

test where part 左連接 lec 視圖 view new manytoone Spring Data JPA 查詢數據庫時,如果兩個表有關聯,那麽就設個外鍵,在查詢的時候用Specification創建Join 查詢便可。但是只支持左連接,不支持右連接,雖說左

Spring Boot中使用Spring-data-jpa實現分頁查詢(轉)

分頁查詢 log def inpu database ext identity odin btn 在我們平時的工作中,查詢列表在我們的系統中基本隨處可見,那麽我們如何使用jpa進行多條件查詢以及查詢列表分頁呢?下面我將介紹兩種多條件查詢方式。 1、引入起步依賴

spring-data-jpa快速入門(二)——簡單查詢

ref spa data mail domain event cif open 寫實 一、方法名解析   1.引言     回顧HelloWorld項目中的dao接口 public interface GirlRepository extends JpaRepos

Mongodb系列- 使用spring-data-mongodb實現分頁查詢

mon 分頁查詢 rep template list pre pri 自動生成 aging 在用spring-data-mongodb框架開發的過程中,需要實現分頁查詢,就百度了下,沒找到滿意的又google了下,找到了思路. 在spring-data-mongodb 官

模糊查詢Spring Data JPA 如何進行模糊查詢(LIKE) ?

定義 repos ppi -- data art dao層 sql語句 pos 原文詳見-----> https://blog.csdn.net/czx1204/article/details/79131281 一. 方法一 1. Controller層: 方

spring data jpa關聯查詢(一對一、一對多、多對多)

sse eager save net array ota println ack generate   在實際過往的項目中,常用的查詢操作有:1、單表查詢,2、一對一查詢(主表和詳情表)3、一對多查詢(一張主表,多張子表)4、多對多查詢(如權限控制,用戶、角色多對多)。做個