【java-Neo4j 5进阶篇】- 1.批量新增数据

系列文章目录

之前的系列文章:
一、概述篇:https://blog.csdn.net/qq_40570699/article/details/143024984
二、入门篇:https://blog.csdn.net/qq_40570699/article/details/143905723
三、进阶篇:

  • 1.批量导入数据

文章目录

  • 系列文章目录
  • 需求场景
  • 一、解决思路
  • 二、代码
    • 1.将属性更新的逻辑封装为一个通用的工具类,可以处理任意类型的对象。
    • 2.在服务端使用上述工具方法封装节点更新逻辑,无需手动处理反射或循环。
    • 3.进一步抽象为通用接口
    • 4.服务扩展
    • 5.代码调用
  • 三、总结


需求场景

代码版本及依赖在该系列入门篇已阐明

1.我需要使用Java向Neo4j新增一批数据。若数据已存在则更新非空属性的值,若不存在则新增节点数据。
2.我的节点实体很多,我想要个能够高复用的抽象代码。


一、解决思路

基于我们对ES的更新思路一致,Neo4j提供的saveAll也需要我们先查询后更新。所以我们先将我们插入的数据分类为已存在数据不存在数据对应的修改新增

二、代码

1.将属性更新的逻辑封装为一个通用的工具类,可以处理任意类型的对象。

代码如下(示例):

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Objects;public class ObjectUtils {/*** 更新目标对象的非空属性* * @param source 源对象,包含最新属性值* @param target 目标对象,将被更新*/public static <T> void updateNonNullProperties(T source, T target) {if (source == null || target == null) {throw new IllegalArgumentException("Source and target objects must not be null");}Field[] fields = source.getClass().getDeclaredFields();for (Field field : fields) {try {field.setAccessible(true);Object value = field.get(source);if (value != null) {field.set(target, value);}} catch (IllegalAccessException e) {throw new RuntimeException("Error updating properties", e);}}}/*** 将一批实体更新到数据库(适用于批量更新场景)** @param sources 待更新的源对象集合* @param existingEntities 已存在的实体集合* @param getIdentifierFunction 用于提取唯一标识符的方法引用* @param saveFunction 保存方法引用* @param <T> 实体类型* @param <ID> 唯一标识符类型*/public static <T, ID> void saveOrUpdateEntities(Collection<T> sources,Collection<T> existingEntities,java.util.function.Function<T, ID> getIdentifierFunction,java.util.function.Consumer<Collection<T>> saveFunction) {// 构建已存在实体的 Map<Identifier, Entity>var existingEntityMap = existingEntities.stream().collect(java.util.stream.Collectors.toMap(getIdentifierFunction, e -> e));// 遍历源数据,更新或新增sources.forEach(source -> {ID identifier = getIdentifierFunction.apply(source);T existingEntity = existingEntityMap.get(identifier);if (existingEntity != null) {updateNonNullProperties(source, existingEntity);} else {existingEntities.add(source); // 新增}});// 保存所有数据saveFunction.accept(existingEntities);}
}

2.在服务端使用上述工具方法封装节点更新逻辑,无需手动处理反射或循环。

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;@Service
public class YourNodeService {private final YourNodeRepository yourNodeRepository;public YourNodeService(YourNodeRepository yourNodeRepository) {this.yourNodeRepository = yourNodeRepository;}/*** 插入或更新节点* * @param nodes 节点列表*/@Transactionalpublic void saveOrUpdateNodes(List<YourNode> nodes) {// 提取所有 name 属性List<String> names = nodes.stream().map(YourNode::getName).toList();// 查询数据库中的已存在节点List<YourNode> existingNodes = yourNodeRepository.findByNameIn(names);// 使用通用工具方法处理更新逻辑ObjectUtils.saveOrUpdateEntities(nodes,existingNodes,YourNode::getName,yourNodeRepository::saveAll);}
}

3.进一步抽象为通用接口

import java.util.List;public interface GenericService<T, ID> {void saveOrUpdate(List<T> entities, java.util.function.Function<T, ID> identifierFunction);
}
import org.springframework.data.repository.CrudRepository;
import org.springframework.transaction.annotation.Transactional;import java.util.List;
import java.util.stream.Collectors;public class GenericServiceImpl<T, ID> implements GenericService<T, ID> {private final CrudRepository<T, ID> repository;public GenericServiceImpl(CrudRepository<T, ID> repository) {this.repository = repository;}@Override@Transactionalpublic void saveOrUpdate(List<T> entities, java.util.function.Function<T, ID> identifierFunction) {// 提取所有标识符List<ID> identifiers = entities.stream().map(identifierFunction).collect(Collectors.toList());// 查询已存在的实体List<T> existingEntities = (List<T>) repository.findAllById(identifiers);// 调用通用工具更新或插入数据ObjectUtils.saveOrUpdateEntities(entities,existingEntities,identifierFunction,repository::saveAll);}
}

4.服务扩展

import org.springframework.stereotype.Service;@Service
public class YourNodeService extends GenericServiceImpl<YourNode, String> {public YourNodeService(YourNodeRepository yourNodeRepository) {super(yourNodeRepository);}
}

5.代码调用

//name为你实体中标准@Id的唯一属性
yourNodeService.saveOrUpdate(nodes, YourNode::getName);

三、总结

  • 复用性强:
    通过通用工具类或服务接口实现,支持不同实体类型的批量更新或插入逻辑。
  • 代码简洁:
    省去每次手写循环处理逻辑,业务层代码更简明。
  • 可扩展性:
    轻松扩展到其他实体类型,只需注入对应的 Repository 和标识符方法。
  • 性能优化:
    避免重复查询数据库,支持批量查询和保存,减少数据库交互次数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/62761.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LWIP和FATFS 实现 FTP 服务端

目录 一、前言 二、LWIP 和 FTP 简介 1.LWIP 2.FTP 三、实现 FTP 服务端的主要步骤 1.初始化 LWIP 2.创建 FTP 服务器任务 3.处理客户端连接 4.实现 FTP 命令处理 5.文件系统操作 6.错误处理和日志记录 四、示例代码 1.创建FTP任务 2. FTP任务代码 3.处理交互数据…

Java基础访问修饰符全解析

一、Java 访问修饰符概述 Java 中的访问修饰符用于控制类、方法、变量和构造函数的可见性和访问权限&#xff0c;主要有四种&#xff1a;public、protected、default&#xff08;无修饰符&#xff09;和 private。 Java 的访问修饰符在编程中起着至关重要的作用&#xff0c;它…

llvm源码编译

0x00 获取llvm源码 获取llvm项目源码&#xff1a;git clone https://github.com/llvm/llvm-project.git 但是&#xff0c;该项目较大&#xff0c;且直接从github下载源码可能会超时失败。可利用gitee的镜像项目进行clone&#xff1a;git clone --depth 1 https://gitee.com/m…

SpringBoot源码-Spring Boot启动时控制台为何会打印logo以及自定义banner.txt文件控制台打印

1.当我们启动一个SpringBoot项目的时候&#xff0c;入口程序就是main方法&#xff0c;而在main方法中就执行了一个run方法。 SpringBootApplication public class StartApp {public static void main(String[] args) {// testSpringApplication.run(StartApp.class);} }publi…

Uniad复现学习

在优云平台部署训练&#xff0c;加速训练。 关于UCloud(优刻得)旗下的compshare算力共享平台 UCloud(优刻得)是中国知名的中立云计算服务商&#xff0c;科创板上市&#xff0c;中国云计算第一股。 UCloud&#xff08;优刻得&#xff09;旗下的Compshare算力共享平台具有以下优点…

数学建模——Topsis法

数模评价类&#xff08;2&#xff09;——Topsis法 概述 Topsis:Technique for Order Preference by Similarity to Ideal Solution 也称优劣解距离法&#xff0c;该方法的基本思想是&#xff0c;通过计算每个备选方案与理想解和负理想解之间的距离&#xff0c;从而评估每个…

基于单片机的四位数码管检测有毒气体

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;通过滑动变阻器连接ADC0832数模转换器模拟有毒气体浓度检测&#xff0c;通过数码管实时显示&#xff0c;如果超过阈值&#xff0c;则蜂鸣器报警&#xff0c;灯光亮起。按…

小程序 - 比较数字大小

小程序交互练习 - 比较数字大小的小程序 目录 比较数字大小 功能描述 准备工作 页面内容 设置页面事件 页面绑定事件 比较大小 按钮绑定事件 比较事件 设置结果显示 页面样式 功能截图 总结 比较数字大小 本案例将实现“比较数字大小”微信小程序&#xff0c;它的…

windows下用mysqld启动免安装mysql

windows系统可以下载免安装版本&#xff0c;就是绿色版&#xff0c;里面包含mysql运行的所有必要条件。 ![[Pasted image 20241128231459.png]] 启动步骤&#xff1a; 解压&#xff0c;然后在解压目录创建my.ini。 [mysqld] # 设置13306端口 port13306# 设置mysql的安装目录…

windows安装itop

本文介绍 win10 安装 itop 安装WAMP集成环境前 先安装visual c 安装itop前需要安装WAMP集成环境(windowsApacheMysqlPHP) 所需文件百度云盘 通过网盘分享的文件&#xff1a;itop.zip 链接: https://pan.baidu.com/s/1D5HrKdbyEaYBZ8_IebDQxQ 提取码: m9fh 步骤一&#xff1…

Leetcode - 周赛425

目录 一&#xff0c;3364. 最小正和子数组 二&#xff0c; 3365. 重排子字符串以形成目标字符串 三&#xff0c;3366. 最小数组和 四&#xff0c;3367. 移除边之后的权重最大和 一&#xff0c;3364. 最小正和子数组 本题可以直接暴力枚举&#xff0c;代码如下&#xff1a; …

微服务即时通讯系统的实现(服务端)----(2)

目录 1. 语音识别子服务的实现1.1 功能设计1.2 模块划分1.3 模块功能示意图1.4 接口的实现 2. 文件存储子服务的实现2.1 功能设计2.2 模块划分2.3 模块功能示意图2.4 接口的实现 3. 用户管理子服务的实现3.1 功能设计3.2 模块划分3.3 功能模块示意图3.4 数据管理3.4.1 关系数据…

Matlab Simulink HDL Coder开发流程(一)— 创建HDL兼容的Simulink模型

创建HDL兼容的Simulink模型 一、使用Balnk DUT模板二、从HDL Coder库中选择模块三、为DUT开发算法/功能四、为设计创建Testbench五、仿真验证设计功能六、Simulink模型生成HDL代码 这个例子说明了如何创建一个用于生成HDL代码的Simulink模型。要创建兼容HDL代码生成的MATLAB算法…

mfc110u.dll是什么意思,mfc110u.dll丢失解决方法大全详解

mfc110u.dll是Microsoft Foundation Classes (MFC)库的一个特定版本&#xff08;版本11.0&#xff09;的Unicode动态链接库文件。MFC是Microsoft为C开发者设计的一个应用程序框架&#xff0c;主要用于简化Windows应用程序的开发工作。这个框架封装了很多Windows API函数&#x…

debian 11 虚拟机环境搭建过坑记录

目录 安装过程系统配置修改 sudoers 文件网络配置换源安装桌面mount nfs 挂载安装复制功能tab 无法补全其他安装 软件配置eclipse 配置git 配置老虚拟机硬盘挂载 参考 原来去 debian 官网下载了一个最新的 debian 12&#xff0c;安装后出现包依赖问题&#xff0c;搞了半天&…

JAVAWeb之CSS学习

前引 CSS&#xff0c;层叠样式表&#xff08;Cascading Style Sheets&#xff09;&#xff0c;能够对网页中元素位置的排版进行像素级精确控制&#xff0c;支持几乎所有的字体字号样式&#xff0c;拥有网页对象和模型样式编辑的能力&#xff0c;简单来说&#xff0c;美化页面。…

macos下brew安装redis

首先确保已安装brew&#xff0c;接下来搜索资源&#xff0c;在终端输入如下命令&#xff1a; brew search redis 演示如下&#xff1a; 如上看到有redis资源&#xff0c;下面进行安装&#xff0c;执行下面的命令&#xff1a; brew install redis 演示效果如下&#xff1a; …

element ui select绑定的值是对象的属性时,显示异常.

需要声明 value-key"value",如果还不行可能是数据类型不一致数字0和字符串0是不一致的. el-select v-model"value" clearable placeholder"Select" value-key"value" style"width: 240px"><!-- <el-option v-for&…

黑马程序员Java笔记整理(day06)

1.继承的特点 2.继承的权限 3. 4.小结 5.方法重写 6.子类构造器 7.兄弟构造器 8.多态 9.小结

VPC9527同步整流控制器,相对最大电压检测与强力自供电,与MP6908完全PIN TO PIN

VPC9527 是一款高性能的同步整流控制器,它兼容 CCM 和 DCM 两种模式,最大工作频率高达 700kHz;可 通过 SEL 引脚的逻辑电压来选择 400nS 或 800nS 两个关断检测的屏蔽时间;可通过 VLC 引脚来调整限压导通的 参数,以便与所选同步整流管的参数相匹配,获得适应的最优性能;它…