当前位置: 首页 > news >正文

图数据库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:7687username: neo4jpassword: 123456database: neo4j

1.3neo扫包

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

2入门代码

2.1代码结构

在这里插入图片描述

2.2node

如下所示,这是我们的一个实际的节点,我们以该节点为例,创建一个UserNode
在这里插入图片描述

//如果你没有使用lombook,请自己手动生成对应的get/set
@Data
@NodeEntity("User")
public class UserNode {@Id@GeneratedValueprivate 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{@Autowiredprivate UserRepository userRepository;@Overridepublic void saveUser(UserNode userNode) {userRepository.save(userNode);}@Overridepublic UserNode getUserById(Long id) {return userRepository.findById(id).orElse(null);}}

2.5controller

@RestController
public class UserController {@Autowiredprivate 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,在重启项目即可。
在这里插入图片描述

2.6验证

通过接口创建User节点,老王 ,然后再neo4j中查询,看能否查到
在这里插入图片描述
根据上面neo4j为我们生成的ID,使用这个ID进行查询,看能否查询到数据

在这里插入图片描述

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@GeneratedValueprivate Long id;private String userName;private int userAge;private String userSex;//和当前这个用户有关系的用户@Relationship(type = "RELATION")private List<UserNode> userNodes;
}

现在我们要实现,根据西子找出关系为RELATION的User节点
在这里插入图片描述
使用我们之前的接口,根据西子的id,查询西子信息即可
在这里插入图片描述
如果我们使用无向的关系,如下所示,就会出现循环嵌套(西子->老司->西子->老司),然后堆栈溢出。

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

在这里插入图片描述
如果我们使用反向的关系,那么根据西子查询,就查询不到了,但是根据念念,能查到西子和老司,因为西子和老司都指向念念,此时关系是逆向的,从终点到起点进行匹配。

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

在这里插入图片描述

3.2Neo4jRepository

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

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

在这里插入图片描述
使用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@GeneratedValueprivate 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

在这里插入图片描述
在这里插入图片描述
可以看到现在西子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.

在这里插入图片描述
现在我们使用S save(S s, int depth),先设置为0,发现只保存西子,没有保存小跟班和孙悟空

西子.setUserAge(18);
西子.getHusband().setUserAge(18);
孙悟空.setUserAge(18);userRepository.save(西子, 0);

在这里插入图片描述

<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保存)
在这里插入图片描述
以查询为例,现在我们想通过名称查询,这是我们之前案例中定义的一个根据名称查询,当时没有说为什么,现在我们来研究一下。

@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是按照什么规则生成的?答案是按照我们定义的方法名来生成的。
在这里插入图片描述
当然通过观察发现,不难看出,那就是这里面,java类属性、neo4j节点属性,java接口名我们都是叫做userName
在这里插入图片描述
如此我们把findByUserName改成findByName,启动项目就报错了,错误提示很明显,那就是在UserNode中没有name这个属性

 No property name found for type UserNode!

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

@Property("userName")
private String name;

在这里插入图片描述

3.3.2findBi属性字段总结

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

Spring Data Neo4j 提供了一组基于命名约定的查询方法,这些方法可以让您使用方法名称来定义查询,而无需编写任何查询语句。这些方法通常以 findBy 开头,后面跟着属性名称,以便指定要匹配的属性。以下是一些常用的 findBy 方法: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():根据指定属性的降序顺序返回所有实体。
其中 Property 表示实体类中的属性名称,T 表示属性的数据类型,Collection<T> 表示属性值的集合。除了上述方法之外,Spring Data Neo4j 还支持许多其他的查询方法,例如 findFirstByProperty、findTop5ByProperty 等。这些方法的命名约定都遵循 findBy 开头的规则,只是在方法名称的末尾添加了一些限制条件。

相关文章:

图数据库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:76…...

UE虚幻引擎 UTextBlock UMG文本控件超过边界区域以后显示省略号

版本 5.2.1 裁剪 - 剪切 - 剪切到边界 裁剪 - 高级 - 溢出策略 - 省略...

Spring Boot实践五 --异步任务线程池

一、使用Async实现异步调用 在Spring Boot中&#xff0c;我们只需要通过使用Async注解就能简单的将原来的同步函数变为异步函数&#xff0c;Task类实现如下&#xff1a; package com.example.demospringboot;import lombok.extern.slf4j.Slf4j; import org.springframework.s…...

<C语言> 动态内存管理

1.动态内存函数 为什么存在动态内存分配&#xff1f; int main(){int num 10; //向栈空间申请4个字节int arr[10]; //向栈空间申请了40个字节return 0; }上述的开辟空间的方式有两个特点&#xff1a; 空间开辟大小是固定的。数组在声明的时候&#xff0c;必须指定数组的…...

【ASPICE】:学习记录

学习记录 ASPICE中文资料什么是ASPICE过程参考模型 ASPICE全称“Automotive Software Process Improvement and Capability dEtermination”&#xff0c;即“汽车软件过程改进及能力评定”模型框架 ASPICE中文资料 主要资料来源 什么是ASPICE 过程参考模型...

图论--最短路问题

图论–最短路问题 邻接表 /* e[idx]:存储点的编号 w[idx]:存储边的距离&#xff08;权重&#xff09; */ void add(int a, int b, int c) {e[idx] b;ne[idx] h[a];w[idx] ch[a] idx ; }1.拓扑排序 给定一个 n 个点 m 条边的有向图&#xff0c;点的编号是 11 到 n&#xf…...

go 结构体 - 值类型、引用类型 - 结构体转json类型 - 指针类型的种类 - 结构体方法 - 继承 - 多态(interface接口) - 练习

目录 一、结构体 1、python 与 go面向对象的实现&#xff1a; 2、初用GO中的结构体&#xff1a;&#xff08;实例化一个值类型的数据&#xff08;结构体&#xff09;&#xff09; 输出结果不同的三种方式 3、实例化一个引用类型的数据&#xff08;结构体&#xff09; 4、…...

盘点16个.Net开源项目

今天一起盘点下&#xff0c;16个.Net开源项目&#xff0c;有博客、商城、WPF和WinForm控件、企业框架等。&#xff08;点击标题&#xff0c;查看详情&#xff09; 一、一套包含16个开源WPF组件的套件 项目简介 这是基于WPF开发的&#xff0c;为开发人员提供了一组方便使用自…...

记录对 require.js 的理解

目录 一、使用 require.js 主要是为了解决这两个问题二、require.js 的加载三、main.js 一、使用 require.js 主要是为了解决这两个问题 实现 js 文件的异步加载&#xff0c;避免网页失去响应&#xff1b;管理模块之间的依赖性&#xff0c;便于代码的编写和维护。 二、require.…...

minio-分布式文件存储系统

minio-分布式文件存储系统 minio的简介 MinIO基于Apache License v2.0开源协议的对象存储服务&#xff0c;可以做为云存储的解决方案用来保存海量的图片&#xff0c;视频&#xff0c;文档。由于采用Golang实现&#xff0c;服务端可以工作在Windows,Linux, OS X和FreeBSD上。配置…...

Kindling the Darkness: A Practical Low-light Image Enhancer论文阅读笔记

这是ACMMM2019的一篇有监督暗图增强的论文&#xff0c;KinD其网络结构如下图所示&#xff1a; 首先是一个分解网络分解出R和L分量&#xff0c;然后有Restoration-Net和Adjustment-Net分别去对R分量和L分量进一步处理&#xff0c;最终将处理好的R分量和L分量融合回去。这倒是很常…...

AcWing 4575. Bi数和Phi数

文章目录 题意:思路:代码 题意: 就是给你n个数&#xff0c;对于每一个数y你都需要找到一个最小x使得 ϕ ( x ) ≥ y \phi(x) \ge y ϕ(x)≥y&#xff0c;然后再求一个最小平和。 思路: 其实最开始以来的思路就是二分&#xff0c;我先进行线性筛求出每个数的欧拉函数&#xf…...

《Federated Unlearning via Active Forgetting》论文精读

文章目录 1、概述2、方法实验主要贡献框架概述 3、实验结果比较方法实验结果忘却完整性忘却效率模型实用性 4、总结 原文链接&#xff1a; Federated Unlearning via Active Forgetting 1、概述 对机器学习模型隐私的⽇益关注催化了对机器学习的探索&#xff0c;即消除训练数…...

Java课题笔记~Maven基础知识

一、什么是Maven&#xff1f; Maven是专门用于管理和构建Java项目的工具。 它的主要功能有&#xff1a; 提供了一套标准化的项目结构提供了一套标准化的构建流程&#xff08;编译&#xff0c;测试&#xff0c;打包&#xff0c;发布……&#xff09;提供了一套依赖管理机制 …...

xcode中如何显示文件后缀

xcode14.3 用不惯mac电脑真恶心&#xff0c;改个显示文件后缀找半天 1、首先双击打开xcode软件 2、此时&#xff0c;电脑左上角出现xcode字样(左上角如果看不到xcode字样&#xff0c;再次点击xcode软件弹出来就有了)&#xff0c;鼠标右键它&#xff0c;点击setting或者Prefere…...

SpringBoot使用JKS或PKCS12证书实现https

SpringBoot使用JKS或PKCS12证书实现https 生成JKS类型的证书 可以利用jdk自带的keytool工具来生成证书文件&#xff0c; 默认生成的是JKS证书 cmd命令如下: 执行如下命令&#xff0c;并按提示填写证书内容&#xff0c;最后会生成server.keystore文件 keytool -genkey tomcat…...

云原生势不可挡,如何跳离云原生深水区?

云原生是云计算领域一大热词&#xff0c;伴随云原生概念而来的是数字产业迎来井喷、数字变革来临、数字化得以破局以及新一波的技术红利等等。云原生即“云”原生&#xff0c;顾名思义是让“应用”最大程度地利用云的能力&#xff0c;发挥云价值的最佳路径。具体来说&#xff0…...

python的decimal或者叫Decimal,BigDecimal

前言 在python中进行小数计算时&#xff0c;很容易发生精度错误问题&#xff01;&#xff01;&#xff01;&#xff01;一定要注意&#xff01;&#xff01;&#xff01;或者说&#xff0c;只要进行小数的运算都要用decimal。如&#xff1a;银企对账&#xff1b;工程计算等等在…...

Mac环境变量问题

查询环境变量 echo $PATH 查询当前使用的Shell&#xff0c;这里注意SHELL需要大写 echo $SHELL >>>如果输出的是/bin/zsh&#xff0c;说明使用的是zsh。zsh读取的个人配置文件是~/.zshrc (mac10.15.x 后对应的是~/.zprofile) >>>如果输出的是/bin/bash&…...

Shell脚本学习-Web服务监控

参考我的博客文章《Centos安装nginx》&#xff0c;先来安装下nginx。我按照该文档操作了一遍&#xff0c;还是很快就能安装好nginx的。 确认可以安装成功&#xff1a; [rootvm1 sbin]# netstat -atunlp |grep 80 tcp 0 0 0.0.0.0:80 0.0.0.0:* …...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

内存分配函数malloc kmalloc vmalloc

内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

UE5 音效系统

一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类&#xff0c;将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix&#xff0c;将上述三个类翻入其中&#xff0c;通过它管理每个音乐…...

js 设置3秒后执行

如何在JavaScript中延迟3秒执行操作 在JavaScript中&#xff0c;要设置一个操作在指定延迟后&#xff08;例如3秒&#xff09;执行&#xff0c;可以使用 setTimeout 函数。setTimeout 是JavaScript的核心计时器方法&#xff0c;它接受两个参数&#xff1a; 要执行的函数&…...

CppCon 2015 学习:REFLECTION TECHNIQUES IN C++

关于 Reflection&#xff08;反射&#xff09; 这个概念&#xff0c;总结一下&#xff1a; Reflection&#xff08;反射&#xff09;是什么&#xff1f; 反射是对类型的自我检查能力&#xff08;Introspection&#xff09; 可以查看类的成员变量、成员函数等信息。反射允许枚…...