图数据库Neo4j学习四Spring Data NEO

这篇具有很好参考价值的文章主要介绍了图数据库Neo4j学习四Spring Data NEO。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1配置

1.1Maven依赖

<!--neo4j  -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>

1.2yml配置

spring:
  data:
    neo4j:
      uri: bolt://localhost:7687
      username: neo4j
      password: 123456
      database: neo4j

1.3neo扫包

@SpringBootConfiguration
@EnableNeo4jRepositories(basePackages = "com.**.repo")
public class NeoConfig {

}

2入门代码

2.1代码结构

spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习

2.2node

如下所示,这是我们的一个实际的节点,我们以该节点为例,创建一个UserNode
spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习

//如果你没有使用lombook,请自己手动生成对应的get/set
@Data
@NodeEntity("User")
public class UserNode {
    @Id
    @GeneratedValue
    private Long id;
    private String userName;
    private int userAge;
    private String userSex;
}

2.3repo

@Repository
public interface UserRepository extends Neo4jRepository<UserNode, Long> {

}

2.4service

public interface UserService {

	void saveUser(UserNode userNode);
	
	UserNode getUserById(Long id);
}

@Service
public class UserServiceImpl implements UserService{

	@Autowired
    private UserRepository userRepository;

	@Override
    public void saveUser(UserNode userNode) {
    	userRepository.save(userNode);
    }
	
	@Override
    public UserNode getUserById(Long id) {
    	return userRepository.findById(id).orElse(null);
    }
	
}

2.5controller

@RestController
public class UserController {
	
    @Autowired
    private UserService userService;
    
    @PostMapping("/user")
    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "新增用户节点")
    public R<String> savePerson(@RequestBody UserNode userNode) {
    	userService.saveUser(userNode);
    	return R.ok();
    }

    @GetMapping("/user/id{id}")
    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "根据ID获取用户节点")
    public R<UserNode> getUserById(@PathVariable Long id) {
    	UserNode user = userService.getUserById(id);
    	return R.ok(user);
    }
}

如果出现以下错误

The client is unauthorized due to authentication failure.

解决方法:找到你安装neo4j的路径下的conf文件夹,neo4j.conf,找到

#dbms.security.auth_enabled=false

将前面的注释#去掉,然后重启neo4j,在重启项目即可。
spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习

2.6验证

通过接口创建User节点,老王 ,然后再neo4j中查询,看能否查到
spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习
根据上面neo4j为我们生成的ID,使用这个ID进行查询,看能否查询到数据

spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习

3spring data neo详解

3.1节点

下面是我们实体类节点中常用的注解。

//表明这个类和节点进行映射
@NodeEntity

//节点的主键ID
@Id

//如果ID为null,生成默认的ID值
@GeneratedValue

//节点的关系
@Relationship
/*
Relationship.UNDIRECTED关系的起点和终点之间没有方向性
Relationship.OUTGOING 表示关系只能从起点指向终点(默认值)
Relationship.INCOMING 表示关系只能从终点指向起点
*/

//java类属性名和neo4j属性名映射
@Property

接下来我们看一个例子。

我们定义了一个UserNode类和User标签节点进行映射,并且,该用户和其他用户存在RELATION的关系

@Data
@NodeEntity("User")
public class UserNode {
    @Id
    @GeneratedValue
    private Long id;
    private String userName;
    private int userAge;
    private String userSex;
    
    //和当前这个用户有关系的用户
    @Relationship(type = "RELATION")
    private List<UserNode> userNodes;
}

现在我们要实现,根据西子找出关系为RELATION的User节点
spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习
使用我们之前的接口,根据西子的id,查询西子信息即可
spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习
如果我们使用无向的关系,如下所示,就会出现循环嵌套(西子->老司->西子->老司),然后堆栈溢出。

@Relationship(type = "RELATION", direction = Relationship.UNDIRECTED)
private List<UserNode> userNodes;

spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习
如果我们使用反向的关系,那么根据西子查询,就查询不到了,但是根据念念,能查到西子和老司,因为西子和老司都指向念念,此时关系是逆向的,从终点到起点进行匹配。

@Relationship(type = "RELATION", direction = Relationship.INCOMING)
private List<UserNode> userNodes;

spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习

3.2Neo4jRepository

加粗样式还记得上面我们的入门案例嘛,我们编写了一个UserRepository来继承了Neo4jRepository,然而我们却没有任何的实现,这是因为Neo4jRepository默认提供了一些常用的方法来满足我们的增删查改

@Repository
public interface UserRepository extends Neo4jRepository<UserNode, Long> {

}

spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习
使用save方法将实体对象保存到Neo4j数据库中。

  1. 如果实体对象的ID为空,则新建一个节点并将实体对象保存到该节点上;
  2. 如果实体对象的ID不为空,则更新该节点的属性值。
<S extends T> S save(S entity);

<S extends T> S save(S s, int depth);

<S extends T> Iterable<S> save(Iterable<S> ses, int depth);

<S extends T> Iterable<S> saveAll(Iterable<S> entities);

因此当我们定义主键id,尽量使用包装类型,比如如果你的主键id设置为数字的,那么不要使用基本数据类型的int、long,而是使用包装类型的Integer、Long,并且最好是建议将新增和修改的UserNode拆成两个,在新增的时候没有属性id,在修改的时候有属性id,防止在新增的时候误传了id,变成修改操作。当然你也可通过其他方式,来进行区分新增或者更新,然后再新增的时候,将id设置为null。

那么S save(S entity)和S save(S s, int depth)有什么区别?

我们先看如下这个关系

@Data
@NodeEntity("User")
public class UserNode {
    @Id
    @GeneratedValue
    private Long id;
    private String userName;
    private int userAge;
    private String userSex;
    
    //和当前这个用户有关系的用户
    @Relationship(type = "老公", direction = Relationship.OUTGOING)
    private UserNode husband;
    
    @Relationship(type = "同事", direction = Relationship.OUTGOING)
    private UserNode colleague;
}

match(u1:User{userName:"西子"})-[f1:老公]->(u2)-[f2:同事]->(u3) return u1,u2,u3

spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习
spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习
可以看到现在西子18岁,小跟班12岁,孙悟空无年龄

@Repository
public interface UserRepository extends Neo4jRepository<UserNode, Long> {
    List<UserNode> findByUserName(String userName);
}
UserNode 西子 = userRepository.findByUserName("西子").get(0);
//将西子和西子老公小跟班的年龄都设置为15岁
西子.setUserAge(15);
西子.getHusband().setUserAge(15);
    	
//Neo4jRepository 只能查询直接关联,因此查询不到小跟班的同事孙悟空
UserNode 孙悟空 = userRepository.findByUserName("孙悟空").get(0);
孙悟空.setUserAge(15);
西子.getHusband().setColleague(孙悟空);
    	
//我们这里将西子、小跟班、孙悟空的年龄都修改为18岁,然后只保存西子
userRepository.save(西子);

我们发现结果中,我们虽然只保存西子这个节点,但是西子的子节点,以及子节点的子节点都会被保存00.

spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习
现在我们使用S save(S s, int depth),先设置为0,发现只保存西子,没有保存小跟班和孙悟空

西子.setUserAge(18);
西子.getHusband().setUserAge(18);
孙悟空.setUserAge(18);

userRepository.save(西子, 0);

spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习

<S extends T> S save(S entity); //会将关联到的子节点,甚至子节点的子节点也会保存

<S extends T> S save(S s, int depth); //按照深度保存,0代表不保存子节点,1代表保存1级子节点

3.3自定义操作

3.3.1findBy属性字段

先说结论,有兴趣你就看分析过程,没兴趣就直接背结论。

  1. 接口的findBy属性字段这个方法中的属性字段要和NodeEntity中的属性必须对应上
  2. 根据NodeEntity中的属性名,生成cypher语句,如果属性名被Property修饰,那么就用Property的值

之前的案例中我们通过Neo4jRepository来演示自带的一些方法,下面的这些方法,我们就不在逐一演示,总的来说,分成三大部分,分别是保存(新增/修改)、查询、删除,而且大多都是根据ID来的,实际开发中可能不符合我们需要,那么我们如何实现这种既不用写cypher,又能实现查询和删除嗯?(注意:保存一般都是根据主键ID保存)
spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习
以查询为例,现在我们想通过名称查询,这是我们之前案例中定义的一个根据名称查询,当时没有说为什么,现在我们来研究一下。

@Repository
public interface UserRepository extends Neo4jRepository<UserNode, Long> {
    List<UserNode> findByUserName(String userName);
}

为什么我们定义了一个接口,然后这个接口什么实现也没有的情况下,这个接口却能按照userName这个属性进行查询?
我们先配置一个打印日志

logging:
  level:
    org.neo4j.ogm.drivers.bolt.request.BoltRequest: DEBUG

如果上述配置配置完毕以后,并没有生效,请看这里面的neo4j使用中常见的问题Spring Data NEO日志无法打印cyper日志
我们观察下面日志,可以发现,当我们执行了我们定义的接口findByUserName以后,接着会执行一个cypher语句,因此很奇怪,这个cypher是按照什么规则生成的?答案是按照我们定义的方法名来生成的。
spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习
当然通过观察发现,不难看出,那就是这里面,java类属性、neo4j节点属性,java接口名我们都是叫做userName
spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习
如此我们把findByUserName改成findByName,启动项目就报错了,错误提示很明显,那就是在UserNode中没有name这个属性

 No property name found for type UserNode!

spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习
那么我们在UserNode中把userName也改成name试试。结果发现,启动项目没有报错。
在我们执行查询的时候,当然也查询不到数据,因为我们发现,此时生成的cypher是查询name属性,但是我们的neo4j中的所User这个标签的节点都没有name这个属性,或者说就算有name这个属性, 也没有name为西子的节点。
spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习
那可能会有人问,那要是我的数据库中的节点名称和我java类的属性名称,不一样那该怎么办?那就使用@Property

@Property("userName")
private String name;

spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习

3.3.2findBi属性字段总结

Spring Data Neo4j 中的 findByXXXXX 方法是根据方法名中的关键字和参数名来生成查询语句的,因此方法名的命名规则是非常重要的,需要严格遵守。但是如果你有使用Spring Data JPA的经验的话,将会变得特别简单因为,这个规则就是和JPA规则一样的。

有兴趣的可以来看一下Spring Data Jpa 语法规则

方法名的解析是通过删除前缀find,By,OrderBy或者Top等关键字开始的,然后对剩下部分进行解析。例如,如果删除By,方法的剩余部分就是一个约束条件,表示需要查询的字段。

以下是一些基本的规则:

  1. 条件关键字(And, Or):And表示查询结果需要满足所有条件,Or表示查询结果满足任一条件即可。例如 findByNameAndId 表示查询名字和ID都匹配的数据。
  2. 比较关键字(LessThan, GreaterThan, Between等):用于进行比较的查询。例如 findByAgeLessThan 表示查询年龄小于参数值的数据。
  3. Like / NotLike / StartingWith / EndingWith / Containing:用于字符串匹配的查询。例如 findByNameLike 表示查询名字匹配给定模式的数据。
  4. OrderBy:用于排序的查询。例如 findByNameOrderByAgeDesc 表示查询名字匹配的数据,并按年龄降序排序。
  5. IgnoreCase:表示在进行字符串匹配时忽略大小写。例如 findByNameIgnoreCase 表示查询名字(忽略大小写)匹配的数据。
  6. IsNull / IsNotNull / IsTrue / IsFalse:用于特定值的查询。例如 findByAgeIsNull 表示查询年龄为null的数据。
  7. Top / First:表示查询结果的数量。例如 findTop10ByAge 表示查询年龄最大的10个数据。

下面是一些使用示例

findByProperty(property):根据指定属性的值进行查询。
findByPropertyIn(Collection<T> values):查询指定属性值在给定集合中的所有实体。
findByPropertyNotIn(Collection<T> values):查询指定属性值不在给定集合中的所有实体。
findByPropertyIsNull():查询指定属性值为 null 的所有实体。
findByPropertyIsNotNull():查询指定属性值不为 null 的所有实体。
findByPropertyLike(String pattern):查询指定属性值匹配给定模式的所有实体。
findByPropertyStartingWith(String prefix):查询指定属性值以给定前缀开头的所有实体。
findByPropertyEndingWith(String suffix):查询指定属性值以给定后缀结尾的所有实体。
findByPropertyContaining(String substring):查询指定属性值包含给定子字符串的所有实体。
findByPropertyOrderByPropertyAsc():根据指定属性的升序顺序返回所有实体。
findByPropertyOrderByPropertyDesc():根据指定属性的降序顺序返回所有实体。

需要注意的是,方法名的查询虽然方便,但是对于复杂的查询可能会变得很长,可读性也会变差。此时可以考虑使用@Query注解,直接写Cypher查询语句。

3.3.3@Query

先来一个比较简单,我们想要查询User标签节点中,有userAge这个属性的节点,先用cypher来查询看看

match (n:User) where n.userAge is not null return n

spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习
接着我们在UserRepository这个接口中,定义一个方法,方法名可以随便取了,不用遵循上面的findByXxxx,然后我们在这个方法上面添加一个注解Query,将我们上面写的cypher放进去,然后调用这个方法看看效果

@Repository
public interface UserRepository extends Neo4jRepository<UserNode, Long> {
	
    List<UserNode> findByUserName(String userName);
    
    @Query("match (n:User) where n.userAge is not null return n")
    List<UserNode> queryAgeIsNotNull();
}

可以看到测试结果,获取的数据就是我们想要的数据,
spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习
现在我们想要传入参数,例如年龄不为空,并且名字是西子的,这时候我们需要用到占位符 $
(备注:在Mybatis中 占位符是 # ,拼接符是 $,在Neo中,只有占位符,并且是 $不是#)

@Query("match (n:User) where n.userAge is not null and n.userName = $userName return n")
List<UserNode> testCypher(@Param("userName") String userName);
/*
 *备注:@Param("userName")可以省略,前提是:$userName和String userName的名称保持一致,
 *如果不一致就需要@Param为String userName起个别名,这个别名得和$userName一样 ,这个和以前的ORM框架基本差不多
 */

spring-boot-starter-data-neo4j,图数据库neo4j,数据库,neo4j,学习文章来源地址https://www.toymoban.com/news/detail-665873.html

到了这里,关于图数据库Neo4j学习四Spring Data NEO的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 图数据库Neo4j学习五渲染图数据库neo4jd3

    本文最终技术架构:neo4jd3 + Spring boot + Spring Data Neo + neo4j 当我们刚开是接触图数据库的时候,我们进行各种关系查询,最终会得到一个拓扑图。和我们以前使用的数据库不一样的是,我们的数据库查询出来是一系列的表。 事实上,我们的图数据返回的的数据是类似于下面这样

    2024年02月11日
    浏览(44)
  • 图数据库Neo4j学习二——cypher基本语法

    名称应以字母字符开头,不以数字开头,名称不应包含符号,下划线除外 可以很长,最多65535( 2^16 - 1) 或65534字符,具体取决于 Neo4j 的版本 名称区分大小写。:PERSON和:Person是:person三个不同的标签,并且n和N是两个不同的变量。 前导和尾随空白字符将被自动删除。例如, 以下

    2024年02月16日
    浏览(49)
  • 图数据库_Neo4j学习cypher语言_常用函数_关系函数_字符串函数_聚合函数_数据库备份_数据库恢复---Neo4j图数据库工作笔记0008

    然后再来看一些常用函数,和字符串函数,这里举个例子,然后其他的 类似   可以看到substring字符串截取函数   可以看到截取成功   聚合函数   这里用了一个count(n) 统计函数,可以看到效果   关系函数,我们用过就是id(r) 可以取出对应的r的id来这样..

    2024年02月12日
    浏览(60)
  • Neo4j:入门基础(二)~ 数据导入Neo4J RDF导入neo4j数据库

    neo4j导入数据的方式有以下几种: Cypher create 语句,为每一条数据写一个create Cypher load csv 语句,将数据转成CSV格式,通过LOAD CSV读取数据。 neo4j-admin import导入 官方提供的Java API - BatchInserter 大牛编写的 batch-import 工具 neo4j-apoc load.csv + apoc.load.relationship 针对实际业务场景,定制

    2023年04月24日
    浏览(74)
  • 图数据库_Neo4j学习cypher语言_使用CQL_构建明星关系图谱_导入明星数据_导入明星关系数据_创建明星关系---Neo4j图数据库工作笔记0009

    首先找到明星数据   可以看到有一个sheet1,是,记录了所有的关系的数据   然后比如我们搜索一个撒贝宁,可以看到撒贝宁的数据   然后这个是构建的CQL语句   首先我们先去启动服务 neo4j console     然后我们再来看一下以前导入的,可以看到导入很简单, 就是上面有CQL 看一下节

    2024年02月12日
    浏览(45)
  • 图数据库_Neo4j学习cypher语言_使用CQL命令002_删除节点_删除属性_结果排序Order By---Neo4j图数据库工作笔记0006

    然后我们再来看如何删除节点   可以看到首先   我们这里   比如我要删除张三 可以看到 match (n:student) where n.name = \\\"张三\\\" delete n 这样就是删除了student集合中,name是张三的节点   然后我们再来看 如何来删除关系 match (n:student)-[r]-(m:student) where n.name=\\\"小

    2024年02月12日
    浏览(51)
  • Neo4j | 保姆级教学之如何清空neo4j数据库

    要清空neo4j数据库,需要进行以下操作: 停止Neo4j服务器,关闭Neo4j的所有连接。 找到 Neo4j 数据库存储的目录,通常是 data/databases/ 。 删除该目录中的所有文件和子目录。 请注意,这将不可逆地删除数据库的所有内容,包括节点、关系和属性等数据。在执行这个操作之前,请

    2024年02月06日
    浏览(53)
  • Neo4j数据库删除数据

    我们使用Neo4j图数据库进行写入数据操作之后,免不了要删除数据的。 但是Neo4j的控制台没有提供快捷的删除按钮,所以我们还是需要通过命令来操作。 如果数据库中的数据量并不大,节点数相对较少,我们可以通过命令行直接删除节点。 此类操作起到清空数据库的效果,但

    2023年04月09日
    浏览(91)
  • neo4j清空数据库

    清空所有Person、 Movie节点及其所有关系 查询任意数据  如果没有, 就说明已经删除成功了 这段代码是用Cypher查询语言编写的,用于清空所有的Person节点、Movie节点以及它们之间的所有关系。让我们逐步解释代码的每个部分: 这部分代码使用MATCH语句来查找图数据库中的所有

    2024年02月14日
    浏览(46)
  • Neo4j 图形数据库

    目录 Neo4j 基础 什么是Neo4j Neo4j 模块构建 Neo4j的主要应用场景 Neo4j 环境搭建 Docker 安装Neo4j Neo4j数据浏览器  Neo4j CQL CQL简介 Neo4j CQL高级 CQL 函数 CQL多深度关系节点 事务 索引 约束 Neo4j之Admin管理员操作 Neo4j - 数据库备份和恢复 调优思路  Neo4j 程序访问 SpringBoot 整合Neo4j

    2024年02月10日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包