Spring Boot整合Neo4j實戰

關於Spring Boot整合Neo4j的介紹很多,但自己上手參考的時候,仍然有些東西雲裏霧裏有點暈。慢慢才摸出正道。

聊記,分享。

 

一、各組件直接的搭檔配合和版本密切相關。版本不合適,配合不上。

   我是用的版本搭檔是:

     Noe4j 3.5.8

     spring data Noe4j 5.1.3.RELEASE (主要包括OGM SUpport、 Spring Data Repository Support)

     利用maven進行jar包管理

    neo4j jar包引入這塊容易暈,和neo4j相關的包很多,例如:

spring-boot-starter-data-neo4j 

neo4j 

spring-data-neo4j

neo4j-ogm-api

neo4j-ogm-bolt-driver
…………

每個是幹什麼的?引哪個,不引哪個?如何引?這是個技術活。需要根據各子項目的需要,搞清楚各個jar包的用途,在合適的位置引入。

å¨è¿éæå¥å¾çæè¿°

我們項目既沒有直接引入neo4j包,更不是引入spring starter相關的neo4j組件,例如:

      <!--neo4j-->
       <!--  <dependency>-->
       <!--      <groupId>org.springframework.boot</groupId>-->
       <!--      <artifactId>spring-boot-starter-data-neo4j</artifactId>-->
        <!-- </dependency>-->
 <!-- https://mvnrepository.com/artifact/org.neo4j/neo4j -->
<!--        <dependency>-->
<!--            <groupId>org.neo4j</groupId>-->
<!--            <artifactId>neo4j</artifactId>-->
<!--            <version>${neo4j.version}</version>-->
<!--        </dependency>-->

 而是在base模塊引入neo4j-ogm-api組件,例:

       <dependency>
            <groupId>org.neo4j</groupId>
            <artifactId>neo4j-ogm-api</artifactId>
            <version>2.1.6</version>
        </dependency>

像JPA使用了ORM一樣,Neo4j使用了對象-圖形映射(Object-Graph Mapping,OGM)的方式來建模。

service模塊引入:

        <!--neo4j-->
        <dependency>
            <groupId>org.neo4j</groupId>
            <artifactId>neo4j-ogm-bolt-driver</artifactId>
            <version>2.1.6</version>
        </dependency>

Neo4j總共有三種連接方式。常用的有兩種,一種是http的連接方式【端口:7474】,一種是Bolt的連接方式【端口:7687】

 

dao模塊引入:

  <dependencies>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-neo4j</artifactId>
            <version>4.2.11.RELEASE</version>
        </dependency>
    </dependencies>

Spring DATA Neo4j存儲庫提供了不同的API來支持不同的場景

  • GraphRepository
  • GraphTemplate
  • CrudRepository
  • PaginationAndSortingRepository

這些是Java類。 每個具有執行Neo4j數據庫操作的特定目的

S.No. Spring 數據 Neo4j 類 用法
1。 GraphRepository 它用於執行Basic Neo4j DB操作。
2。 GraphTemplate 像其他模塊一樣,它是執行Neo4j DB操作的Spring模板。
3。 CrudRepository 它用於使用Cypher查詢語言(CQL)執行Neo4j CRUD操作。
4。 PaginationAndSortingRepository 它用於執行Neo4j CQL查詢結果的分頁和排序。

我們只需要使接口繼承Neo4jRepository就可以使用該接口提供的一些基礎的增刪改查方法。

@Repository
public interface BotRepository extends Neo4jRepository<BotNode,Long> {
    BotNode findAllByName(String name);

}

對於複雜的查詢我們可以參照上面講到的CQL語句執行。

@Repository
public interface BotRelationRepository extends Neo4jRepository<BotRelation,Long> {
    //返回節點n以及n指向的所有節點與關係
    @Query("MATCH p=(n:Bot)-[r:BotRelation]->(m:Bot) WHERE id(n)={0} RETURN p")
    List<BotRelation> findAllByBotNode(BotNode botNode);

    //返回節點n以及n指向或指向n的所有節點與關係
    @Query("MATCH p=(n:Bot)<-[r:BotRelation]->(m:Bot) WHERE m.name={name} RETURN p")
    List<BotRelation> findAllBySymptom(@Param("name") String name);

    //返回節點n以及n指向或指向n的所有節點以及這些節點間的所有關係
    @Query("MATCH p=(n:Bot)<-[r:BotRelation]->(m:Bot)<-[:BotRelation]->(:Bot)<-[:BotRelation]->(n:Bot) WHERE n.name={name} RETURN p")
    List<BotRelation> findAllByStartNode(@Param("name") String name);


}

二、 application.yml配置neo4j庫訪問信息

neo4j默認密碼爲neo4j登錄時會提示修改密碼 此爲修改後的密碼

  data:
    neo4j:
      uri: bolt://10.143.151.27:7687
      username: neo4j
      password: xxxneo4j

三、Neo4j實戰遇到的一些問題解決記錄

(1)Neo4j刪除節點和關係、徹底刪除節點標籤名

此處給出原文總結:

【1】先刪關係,再刪節點

【2】當記不得關係名時,type(r)可以查到關係名

【3】徹底刪除節點標籤名,需要刪除前期對該標籤名建立的索引

具體參考:https://www.jianshu.com/p/59bd829de0de

 

(2)怎麼合併相同節點?Neo4j圖數據庫爲什麼可以重複插入同一條數據,怎麼可以不重複插入

CREATE (ww:DatabaseConnection { ConnectionId:'c338df71cdcf85ebadac1aab31e25b3f',ConnectionHost:'localhost',ConnectionPort:'1521',ConnectionSeverName:'TESTUSE',ConnectionUserName:'system',ConnectionPassword:'orcl'})

比如這樣一條語句,我執行兩次會產生兩個一樣的節點

使用merge 關鍵字
merge  (n:person{id:1})  set n+={id:1,name:'lz',age:18} return n

當person節點屬性 id=1 匹配時 ,更新該節點,若不存在則創建該節點。  

具體參考:http://neo4j.com.cn/topic/595229bf4ee6742c0459236e

(3)@JsonIdentityInfo的使用:

使用註解@JsonIdentityInfo是防止查詢數據時引發遞歸訪問效應,註解@NodeEntity標誌這個類是一個節點實體,註解@GraphId定義了節點的一個唯一性標識,它將在創建節點時由系統自動生成,所以它是不可缺少的。

@JsonIdentityInfo(generator=JSOGGenerator.class)
@NodeEntity
public class Actor {
    @GraphId Long id;
    private String name;
    private int born;

    public Actor() { }

代碼清單2-22是電影節點實體建模,註解@Relationship表示List是一個關係列表,其中type設定了關係的類型,direction設定這個關係的方向,Relationship.INCOMING表示以這個節點爲終點。addRole定義了增加一個關係的方法。
代碼清單2-22 電影節點實體建模

@JsonIdentityInfo(generator=JSOGGenerator.class)
@NodeEntity
public class Movie {
    @GraphId Long id;
    String title;
    String year;
    String tagline;
    @Relationship(type="ACTS_IN", direction = Relationship.INCOMING)
    List<Role> roles = new ArrayList<>();
public Role addRole(Actor actor, String name){
    Role role = new Role(actor,this,name);
    this.roles.add(role);
    return role;
}

public Movie() { }

代碼清單2-23是角色的關係實體建模,註解@RelationshipEntity表明這個類是一個關係實體,並用type指定了關係的類型,其中@StartNode指定起始節點的實體,
@EndNode指定終止節點的實體,這說明了圖中一條有向邊的起點和終點的定義。其中定義了一個創建關係的構造函數Role(Actor actor,Movie movie,String name),這裏的name參數用來指定這個關係的屬性。
代碼清單2-23 角色關係實體建模

@JsonIdentityInfo(generator=JSOGGenerator.class)
@RelationshipEntity(type = "ACTS_IN")
public class Role {
    @GraphId
    Long id;
    String role;
    @StartNode
    Actor actor;
    @EndNode
    Movie movie;

    public Role() {
    }

    public Role(Actor actor, Movie movie, String name) {
        this.actor = actor;
        this.movie = movie;
        this.role = name;
    }

(4)如果你是使用Spring boot2.0以上,在你創建項目完成後,啓動程序報錯:

Caused by: java.lang.ClassNotFoundException: org.neo4j.ogm.drivers.http.driver.HttpDriver
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_111]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_111]
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) ~[na:1.8.0_111]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_111]
    at java.lang.Class.forName0(Native Method) ~[na:1.8.0_111]
    at java.lang.Class.forName(Class.java:264) ~[na:1.8.0_111]
    at org.neo4j.ogm.session.SessionFactory.newDriverInstance(SessionFactory.java:92) ~[neo4j-ogm-core-3.1.0.jar:3.1.0]
    ... 45 common frames omitted

 

原因是缺少依賴,解決方法是導入缺少的依賴:

<dependency>
            <groupId>org.neo4j</groupId>
            <artifactId>neo4j-ogm-http-driver</artifactId>
        </dependency>

 

(5)新建節點類,id的屬性爲Long而不能爲long

還需要注意的是在Spring boot1.5中修飾id屬性的註釋爲@GraphIdorg.neo4j.ogm.annotation.Id不存在,效果一樣,都是Neo4j數據庫自動創建的ID值。

 @Id
    @GeneratedValue
    private Long id; //id

(6)測試更新數據:

    @Test
    public void updata(){
        Movie movie = movieRepository.findAllById(8183l);
        movie.setName("《迪迦》");
        movieRepository.save(movie);
        System.out.println(movieRepository.findAll());
    }

執行程序,報錯:

java.lang.NullPointerException

我們看到程序執行的CQL語句爲:

MATCH (n:`Movie`) WHERE n.`id` = { `id_0` } WITH n RETURN n, ID(n)

然後我們在Neo4j瀏覽器控制檯執行查詢語句:

這是爲什麼呢?在Neo4j中,根據Id查詢節點的語句爲:

MATCH (n:Movie) where id(n)=8183  RETURN n

我們修改Repository層的查詢方法:

@Repository
public interface MovieRepository extends Neo4jRepository<Movie, Long> {
    @Query("MATCH (n:Movie) where id(n)={id}  RETURN n")
    Movie findAllById(@Param("id") Long id);
}

再次執行更新程序,結果爲:

[Movie{id=8183, name='《迪迦》'}]

 

四、更多參考

https://www.2cto.com/database/201801/713556.html

https://blog.csdn.net/zt15732625878/article/details/98797467

https://www.jianshu.com/p/df99fe312c04

https://yq.aliyun.com/articles/89699/

https://docs.spring.io/spring-data/neo4j/docs/5.1.3.RELEASE/reference/html/

Cypher語言

https://blog.csdn.net/ainuser/article/details/72268344

關於Neo4j和Cypher批量更新和批量插入優化的5個建議

https://blog.csdn.net/hwz2311245/article/details/60963383

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章