关于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组件,例如:
而是在base模块引入neo4j-ogm-api组件,例:
org.neo4j
neo4j-ogm-api
2.1.6
像JPA使用了ORM一样,Neo4j使用了对象-图形映射(Object-Graph Mapping,OGM)的方式来建模。
service模块引入:
org.neo4j
neo4j-ogm-bolt-driver
2.1.6
Neo4j总共有三种连接方式。常用的有两种,一种是http的连接方式【端口:7474】,一种是Bolt的连接方式【端口:7687】
dao模块引入:
org.springframework.data
spring-data-neo4j
4.2.11.RELEASE
Spring DATA Neo4j存储库提供了不同的API来支持不同的场景
这些是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 findAllByName(String name);
}
对于复杂的查询我们可以参照上面讲到的CQL语句执行。
@Repository
public interface BotRelationRepository extends Neo4jRepository {
//返回节点n以及n指向的所有节点与关系
@Query("MATCH p=(n:Bot)-[r:BotRelation]->(m:Bot) WHERE id(n)={0} RETURN p")
List findAllByBotNode(BotNode botNode);
//返回节点n以及n指向或指向n的所有节点与关系
@Query("MATCH p=(n:Bot)<-[r:BotRelation]->(m:Bot) WHERE m.name={name} RETURN p")
List 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 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 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
原因是缺少依赖,解决方法是导入缺少的依赖:
org.neo4j
neo4j-ogm-http-driver
(5)新建节点类,id
的属性为Long
而不能为long
还需要注意的是在Spring boot1.5中修饰id
属性的注释为@GraphId
,org.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 {
@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/
https://blog.csdn.net/ainuser/article/details/72268344
https://blog.csdn.net/hwz2311245/article/details/60963383