TL;DR
- 场景:在 Spring Boot 中整合 Neo4j,需要兼顾手写 Cypher 与实体映射、事务与多层封装。
- 结论:优先基于 SDN6 的 Java Driver 路线(Neo4jClient/Neo4jTemplate/Repository),避免 OGM/嵌入式混搭。
- 产出:分层架构要点、依赖与版本配套建议、常见错误定位与修复清单。

版本矩阵
| 状态 | 说明 |
|---|---|
| ✅ 已验证 | 推荐(Boot 2.4.x + SDN6 + Neo4j 4.1--4.4) |
- 由 spring-boot-starter-data-neo4j 管理 Java Driver 4.x,不再引入 OGM |
|
- @Query 使用 $param + @Param |
|
- 可选配置 spring.neo4j.database |
|
| ⏳ 可行 | Boot 3.x + 当代 SDN + Neo4j 5.x |
| - 要求 Java 17+,Driver 5.x | |
| - 配置项与自动配置更新,注意迁移指南与 API 变化 | |
| ✅ 历史 | Boot 2.3.x 及以下 + SDN5 + Neo4j 3.5.x + OGM |
| - 仅维护旧项目 | |
- 基于 neo4j-ogm,注解/会话模型不同,与 SDN6 架构不一致 |
|
| - 不建议新项目采用 | |
| ⚠️ 高风险混搭 | 你的 POM:Boot 2.4.1 + SDN6 + neo4j-ogm-bolt-driver:3.2.10 + org.neo4j:neo4j:3.5.5 |
| - SDN6 已弃用 OGM | |
- org.neo4j:neo4j 为嵌入式内核依赖,易引发类冲突/行为不一致 |
|
| - 建议清理依赖并匹配服务端 4.x/5.x |
Neo4j Spring Boot 整合
整体架构

整体分层概览
从下到上可以分成六层:
- Neo4j 数据库
- Neo4j Java Driver(Bolt 协议)
- Neo4jClient / Neo4jTemplate(底层访问与模板封装)
- 映射层(MappingContext + MappingInfrastructure)
- Repository 抽象层(Neo4jRepository 等)
- Spring / Spring Boot 集成层(配置、事务、审计、事件)
底层 Neo4j Java Driver
职责:
- 维护与 Neo4j 的网络连接(Bolt 协议)。
- 管理 Session、Transaction、Result。
- 提供最原始的 Cypher 执行接口。
核心点:
- Driver:全局连接入口,对应 neo4j://... 或 bolt://... 地址。
- Session:一次会话,包含事务边界与路由信息。
- Transaction:在 Session 上开启,读写/只读等模式。
- Result 映射:返回的每条记录是 org.neo4j.driver.Record,内部是 Value 类型。
Spring Data Neo4j 不自己去写驱动,而是完全构建在 Java Driver 之上,所有访问最终都会落到这里。
访问层 Neo4jClient 与 Neo4jTemplate
这一层是 Spring Data Neo4j 提供的"对 Driver 的 Spring 风格封装"。
Neo4jClient
定位:轻量、底层、以 Cypher 为中心的客户端。
主要能力:
- 构建和执行 Cypher 语句:
- neo4jClient.query("MATCH ...").bind(...).to(...).run()
- 绑定参数、选择数据库、控制读写模式。
- 映射结果到任意类型(手动指定 Row → Object 的映射)。
使用场景:
- 你需要精细控制 Cypher。
- 想自己写投影映射逻辑、不完全依赖实体映射。
Neo4jTemplate
在 Neo4jClient 之上,增加"实体视角"。
主要职责:
- 提供基于实体类的 CRUD:save, findById, deleteById, findAll 等。
- 负责在"实体 ↔ 图结构"之间做映射。
- 内部会使用 MappingContext、MappingInfrastructure 来处理节点/关系转换。
使用场景:
- 想要面向实体操作,但还不想使用 Repository 抽象。
- 写一些自定义的查询逻辑时,可以在 Service 里直接注入 Neo4jTemplate。
映射层:实体建模与映射基础设施
这层是 Spring Data 系列的核心:如何把 Java 对象映射到 Neo4j 的节点和关系。
实体模型
通过注解描述图模型:
- @Node:标记图节点实体,对应一个 Label。
- @Id / @GeneratedValue:标识主键,可使用数据库生成的 internal id 或自定义业务 id。
- @Property:属性字段(通常可省略,默认字段名→属性名)。
- @Relationship:关系字段,描述边的类型、方向、多重性等。
- @CompositeProperty:映射 Map 等复合属性。
- @DynamicLabels:动态标签支持。
你写的实体类只负责"结构描述",不负责查询;查询由上层 Repository/Template 做。
MappingContext
MappingContext 是 Spring Data 的公共概念,在 SDN 中用来维护:
- 实体元数据:每个实体类有哪些字段、标签、Id 类型、关系配置。
- 实例级缓存:在一次查询 / 一次事务内,保证同一个节点不会被映射成多个不同对象(避免重复实例)。
- 管理对象之间的引用关系,处理关联加载、循环引用。
这保证:
- 同一个节点在图查询中被多次命中时,最后在 Java 里是同一个对象引用。
- 更新时能正确识别哪些实体需要做 SET/DELETE 等。
MappingInfrastructure / Converters
MappingInfrastructure 由多部分组成:
- Neo4jPersistentEntity / Neo4jPersistentProperty:实体和字段的元数据描述。
- ConversionService:类型转换(如 LocalDateTime ↔ Neo4j temporal type)。
- EntityInstantiators:实体实例化策略(包括有参构造函数、Builder 等)。
作用:
- 从 Neo4j Record 构造实体:
- 节点 → 主实体对象。
- 关系 + 目标节点 → 关系字段上的对象(或集合)。
- 从实体构造写回语句:
- 生成 MERGE/MATCH + SET + 关系创建/删除的 Cypher。
抽象层 Repository
Repository 是大部分业务代码接触 Spring Data Neo4j 的主要入口。
Repository 接口家族
- Neo4jRepository<T, ID>:基础接口,继承了 PagingAndSortingRepository、CrudRepository。
- 可选扩展:ReactiveNeo4jRepository<T, ID> 用于响应式。
方法解析与查询生成
Repository 层的核心机制:
Spring 扫描到你的接口,创建代理对象。
每个方法根据规则执行不同策略:
- 方法名解析(derived queries):findByName → 自动生成 Cypher 的 WHERE 条件。
- @Query 注解:使用你提供的原始 Cypher。
- Query by Example(QBE):用 Example 去构建动态查询。
Repository 内部会调用 Neo4jTemplate / Neo4jClient 执行,返回结果经过映射层构建实体。
架构视角:
• Repository 是"DSL + 声明式接口"。
• Template/Client 是"命令式 API"。
• 映射层把"结果记录"升维成"实体图对象"。
XML
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>icu.wzk</groupId>
<artifactId>neo4j-01</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/>
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-bolt-driver</artifactId>
<version>3.2.10</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
实体类
java
package icu.wzk;
import org.springframework.data.neo4j.core.schema.*;
import java.util.Set;
@Node
public class Person {
@Id
@GeneratedValue
private Long id;
@Property("cid")
private int pid;
@Property
private String name;
private double money;
private int gender;
private int age;
private String description;
@Relationship(type = "Friends", direction = Relationship.Direction.INCOMING)
private Set<Person> relationPersons;
// set get 方法省略
// 构造方法
}
DAO层
java
package icu.wzk.dao;
import icu.wzk.Person;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.query.Query;
import java.util.List;
public interface PersonRepository extends Neo4jRepository<Person,Long> {
@Query("match(p:Person) where p.money > {0} return p")
List<Person> personList(double money);
}
application.yml
yaml
spring:
neo4j:
authentication:
password: 123123
username: neo4j
uri: bolt://10.10.52.38:7687
编写服务类
java
package icu.wzk.service;
import icu.wzk.Person;
import icu.wzk.dao.PersonRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class PersonService {
@Autowired
private PersonRepository personRepository;
public List<Person> personList(){
return personRepository.personList(1000);
}
}
编写启动测试
java
package icu.wzk;
import icu.wzk.service.PersonService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import java.util.List;
@SpringBootApplication
public class StartApp {
public static void main(String[] args) {
ApplicationContext app = SpringApplication.run(StartApp.class);
PersonService personService = app.getBean(PersonService.class);
List<Person> data = personService.personList();
for (Person each : data) {
System.out.println(each);
}
}
}
测试结果

错误速查
| 症状 | 根因定位 | 修复方法 |
|---|---|---|
启动时报 NoSuchMethodError/ClassCastException |
SDN6 与 neo4j-ogm/嵌入式内核混搭 |
检查 mvn dependency:tree 是否含 neo4j-ogm*/org.neo4j:neo4j,移除OGM与嵌入式依赖,仅保留spring-boot-starter-data-neo4j |
@Query 报参数找不到/无法绑定 |
使用 {0} 占位与 SDN6 不兼容 |
查看异常与仓库方法签名,改为 $param + @Param("param") 形式 |
| 查询无结果但无异常 | 关系类型大小写或方向不匹配 | 用浏览器 MATCH 验证关系,统一类型(建议全大写)与方向,必要时调整注解 |
| 保存失败或更新错乱 | 依赖内部ID,自引用/聚合关系复杂 | 打印日志查看Cypher与ID,改用业务主键或UUID;审查实体等价性与集合去重 |
| 连接失败/多库访问异常 | 未设置 spring.neo4j.database(Neo4j 4+多库) |
日志出现默认库不匹配时,在配置中显式指定数据库名 |
| 事务中读写不一致 | 缺少事务边界或读写模式设置不当 | 检查 @Transactional 与调用栈,读方法设readOnly=true,写方法显式事务;必要时使用Neo4jClient读写模式 |
映射 StackOverflow/重复对象 |
映射上下文缓存一致性(代码构造关系时环引用) | 观察日志与对象图,交由Template/Repository映射;避免手写递归拼装 |
| 驱动版本不匹配导致握手失败 | 服务端5.x,客户端Driver 4.x(或反之) | 日志含Bolt协议/握手错误时,升级/降级到匹配的Driver主版本(随Boot BOM) |
其他系列
🚀 AI篇持续更新中(长期更新)
AI炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究 ,持续打造实用AI工具指南!
AI-调查研究-108-具身智能 机器人模型训练全流程详解:从预训练到强化学习与人类反馈
🔗 AI模块直达链接
💻 Java篇持续更新中(长期更新)
Java-154 深入浅出 MongoDB 用Java访问 MongoDB 数据库 从环境搭建到CRUD完整示例
MyBatis 已完结,Spring 已完结,Nginx已完结,Tomcat已完结,分布式服务正在更新!深入浅出助你打牢基础!
🔗 Java模块直达链接
📊 大数据板块已完成多项干货更新(300篇):
包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!
大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解
🔗 大数据模块直达链接