使用 MyBatis 操作 Nebula Graph 的实践
我最近注意到很多同学对于 ORM 框架的需求比较迫切,而且有热心的同学已经捐赠了自己开发的项目,Nebula 社区也在 working on it。下面主要介绍一下我们在使用 MyBatis 操作 Nebula Graph 方面的一些经验,希望能够帮助到大家。
MyBatis
Java 开发的同学想必对 MyBatis 都比较熟悉了。MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射,并且免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
实现途径
主要通过 MyBatis 结合 nebula-jdbc 来实现参数返回值映射以及语句执行。
Demo 示例
完整代码参见 GitHub。
Nebula Schema
CREATE SPACE basketballplayer(partition_num=10,replica_factor=1,vid_type=fixed_string(32));
CREATE TAG IF NOT EXISTS player(name string, age int);
CREATE EDGE IF NOT EXISTS follow(degree int);
工程结构
application.yaml
spring:
datasource:
driver-class-name: com.vesoft.nebula.jdbc.NebulaDriver
url: jdbc:nebula://localhost:9669/basketballplayer
username: nebula
password: nebula
hikari:
maximum-pool-size: 20
mybatis:
mapper-locations: classpath:mapper/*.xml
DO
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PlayerDO {
/**
* vid
*/
private String id;
private String name;
private Long age;
}
Dao
public interface PlayerDao {
int insert(PlayerDO entity);
int update(PlayerDO entity);
int insertBatch(List<PlayerDO> batch);
PlayerDO select(String id);
List<PlayerDO> selectBatch(List<String> batch);
int delete(String id);
int deleteBatch(List<String> batch);
//以上代码自动生成
PlayerDO selectReturnV(String id);
}
Mapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dao.PlayerDao">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.example.pojo.PlayerDO">
<result column="id" property="id" jdbcType="VARCHAR"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<result column="age" property="age" jdbcType="BIGINT"/>
</resultMap>
<!-- 插入点或边 -->
<insert id="insert" parameterType="com.example.pojo.PlayerDO">
insert vertex `player` (
<trim suffixOverrides=",">
<if test="name != null">
name,
</if>
<if test="age != null">
age,
</if>
</trim>
) values #{id} :(
<trim suffixOverrides=",">
<if test="name != null">
#{name},
</if>
<if test="age != null">
#{age},
</if>
</trim>
)
</insert>
<!-- 批量插入点或边-->
<insert id="insertBatch" parameterType="com.example.pojo.PlayerDO">
insert vertex `player`
<trim prefix="(" suffix=")" suffixOverrides=",">
name,
age,
</trim>
values
<foreach collection="list" item="item" separator=",">
#{item.id} :
<trim prefix="(" suffix=")" suffixOverrides=",">
#{item.name},
#{item.age},
</trim>
</foreach>
</insert>
<!-- 更新点或边 -->
<update id="update" parameterType="com.example.pojo.PlayerDO">
UPDATE vertex ON `player` #{id}
<trim prefix="set" suffixOverrides=",">
<if test="name != null">
name = #{name},
</if>
<if test="age != null">
age = #{age},
</if>
</trim>
</update>
<!-- 查询点 -->
<select id="select" resultType="com.example.pojo.PlayerDO">
match (v:`player`) where id(v) == #{id} return
<trim suffixOverrides=",">
id(v) as id,
v.name as name,
v.age as age,
</trim>
</select>
<!-- 批量查询点 -->
<select id="selectBatch" resultType="com.example.pojo.PlayerDO">
match (v:`player`) where id(v) in [
<foreach collection="list" item="item" separator=",">
#{item}
</foreach>
] return
<trim suffixOverrides=",">
id(v) as id,
v.name as name,
v.age as age,
</trim>
</select>
<!-- 删除点或边 -->
<delete id="delete" parameterType="java.lang.String">
delete vertex #{id}
</delete>
<!-- 批量删除点或边 -->
<delete id="deleteBatch"
parameterType="java.lang.String">
delete vertex
<foreach collection="list" item="item" separator=",">
#{item}
</foreach>
</delete>
<!--以上代码自动生成-->
<select id="selectReturnV" resultMap="BaseResultMap">
match (v:`player`) where id(v) == #{id} return v
</select>
</mapper>
Tag 操作
@SpringBootTest
public class PlayerDaoTest {
@Resource
private PlayerDao playerDao;
@Test
public void operation() {
//insert
PlayerDO player = PlayerDO.builder().id("daiyi").name("daiyi").age(22l).build();
playerDao.insert(player);
//insertBatch
PlayerDO playerBatch = PlayerDO.builder().id("daiyi").name("daiyi").age(22l).build();
PlayerDO joe = PlayerDO.builder().id("joe").name("joe").age(24l).build();
playerDao.insertBatch(Lists.newArrayList(playerBatch, joe));
//update
playerDao.update(PlayerDO.builder().id("daiyi").name("daiyiupdate").build());
//select
PlayerDO playerDO = playerDao.select("daiyi");
//selectBatch
List<PlayerDO> players = playerDao.selectBatch(Lists.newArrayList("daiyi", "joe"));
//selectReturnV
playerDao.selectReturnV("daiyi");
//delete
playerDao.delete("daiyi");
//deleteBatch
playerDao.deleteBatch(Lists.newArrayList("daiyi", "joe"));
}
}
Edge 及 Path 操作
篇幅有限,详情可以参见github。
版本适配
目前仅支持了 Nebula 2.5 版本,后续版本的支持还在适配中。
总结
优点
- 使用简单,消除了使用 JDBC 或 nebula-client 带来的冗余代码。
- 可以使用配套连接池管理连接,并且可以与 Spring Boot 无缝衔接。
- nGQL 与代码解耦,方便管理。
- 大量便捷标签,免除了代码拼接语句的烦恼。
存在的问题
- 针对返回值为 Vertex(类似
MATCH v RETURN v)、Edge、无属性 Path 的类型目前采用在 MyBatis 中的 Interceptor 做拦截处理,也能满足使用。但这种实现方式感觉不是很好,后期有待优化。 - 对于返回值类型为带属性 Path、多 Tag 查询以及 GET SUBGRAPH 语句的情况,因为返回的结果中实体以及边的类型可能有多种,目前没有想到比较好的映射方式也就没有支持。
- 上述示例中使用的 JDBC 驱动是我们自己开发的版本(详见 https://github.com/DA1Y1/nebula-jdbc),与社区版的主要区别在 URL 上服务地址的指定以及⼀些转义字符的处理,后续也希望能将这些 Feature 合并到社区版本中,统⼀使⽤。
为了方便使用我们还开发了类似 mybatis-generator 这种工具来生成一些基础代码,提供基本的增删改查功能。感兴趣的同学可以在 IDEA 的 Plugins 中搜索 Nebula Generator 下载,使用方式参见:https://plugins.jetbrains.com/plugin/18026-nebula-generator
最后感谢 @DA1Y1 以及其他几位小伙伴的贡献!
交流图数据库技术?加入 Nebula 交流群请先填写下你的 Nebula 名片,Nebula 小助手会拉你进群~~
使用 MyBatis 操作 Nebula Graph 的实践的更多相关文章
- Neo4j 导入 Nebula Graph 的实践总结
摘要: 主要介绍如何通过官方 ETL 工具 Exchange 将业务线上数据从 Neo4j 直接导入到 Nebula Graph 以及在导入过程中遇到的问题和优化方法. 本文首发于 Nebula 论坛 ...
- 分布式图数据库 Nebula Graph 的 Index 实践
导读 索引是数据库系统中不可或缺的一个功能,数据库索引好比是书的目录,能加快数据库的查询速度,其实质是数据库管理系统中一个排序的数据结构.不同的数据库系统有不同的排序结构,目前常见的索引实现类型如 B ...
- Nebula Graph 在微众银行数据治理业务的实践
本文为微众银行大数据平台:周可在 nMeetup 深圳场的演讲这里文字稿,演讲视频参见:B站 自我介绍下,我是微众银行大数据平台的工程师:周可,今天给大家分享一下 Nebula Graph 在微众银行 ...
- Nebula Graph 的 Ansible 实践
本文首发于 Nebula Graph 公众号 NebulaGraphCommunity,Follow & 看大厂图数据库技术实践 背景 在 Nebula-Graph 的日常测试中,我们会经常在 ...
- Nebula Graph 在网易游戏业务中的实践
本文首发于 Nebula Graph Community 公众号 当游戏上知识图谱,网易游戏是如何应对大规模图数据的管理问题,Nebula Graph 又是如何帮助网易游戏落地游戏内复杂的图的业务呢? ...
- GraphX 在图数据库 Nebula Graph 的图计算实践
不同来源的异构数据间存在着千丝万缕的关联,这种数据之间隐藏的关联关系和网络结构特性对于数据分析至关重要,图计算就是以图作为数据模型来表达问题并予以解决的过程. 一.背景 随着网络信息技术的飞速发展,数 ...
- 解析 Nebula Graph 子图设计及实践
本文首发于 Nebula Graph 公众号 NebulaGraphCommunity,Follow 看大厂图数据库技术实践. 前言 在先前的 Query Engine 源码解析中,我们介绍了 2.0 ...
- 分布式图数据库 Nebula Graph 中的集群快照实践
1 概述 1.1 需求背景 图数据库 Nebula Graph 在生产环境中将拥有庞大的数据量和高频率的业务处理,在实际的运行中将不可避免的发生人为的.硬件或业务处理错误的问题,某些严重错误将导致集群 ...
- Nebula Graph 技术总监陈恒:图数据库怎么和深度学习框架进行结合?
引子 Nebula Graph 的技术总监在 09.24 - 09.30 期间同开源中国·高手问答的小伙伴们以「图数据库的设计和实践」为切入点展开讨论,包括:「图数据库的存储设计」.「图数据库的计算设 ...
- 图数据库 Nebula Graph 的安装部署
Nebula Graph:一个开源的分布式图数据库.作为唯一能够存储万亿个带属性的节点和边的在线图数据库,Nebula Graph 不仅能够在高并发场景下满足毫秒级的低时延查询要求,还能够实现服务高可 ...
随机推荐
- Redis做Mybatis的二级缓存
Redis做mybatis的二级缓存 作用提升速度,保证多台服务器访问同一数据库时不会崩 注意:保证本地有下载redis且已经打开,否则无法使用. [本文只讲述了实现步骤,并没有原理讲解] 保证有导入 ...
- JS 逆向之 Hook,吃着火锅唱着歌,突然就被麻匪劫了!
关注微信公众号:K哥爬虫,QQ交流群:808574309,持续分享爬虫进阶.JS/安卓逆向等技术干货! 什么是 Hook? Hook 中文译为钩子,Hook 实际上是 Windows 中提供的一种用以 ...
- 补齐短板-开源IM项目OpenIM关于初始化/登录/好友接口文档介绍
OpenIM文档方面的建设一直远远落后于开发, 也经常被开发者诟病,在接下来一周的时间里,我们重点补齐文档,让开发者更轻松接入.由于app sdk底层都是go来实现,所以本文先写一个模板和框架,在接下 ...
- 第三届人工智能,大数据与算法国际学术会议 (CAIBDA 2023)
第三届人工智能,大数据与算法国际学术会议 (CAIBDA 2023) 大会官网:http://www.caibda.org/ 大会时间:2023年6月16-18日 大会地点:中国郑州 截稿日期:2 ...
- 强化学习从基础到进阶-常见问题和面试必知必答[7]:深度确定性策略梯度DDPG算法、双延迟深度确定性策略梯度TD3算法详解
强化学习从基础到进阶-常见问题和面试必知必答[7]:深度确定性策略梯度DDPG算法.双延迟深度确定性策略梯度TD3算法详解 1.核心词汇 深度确定性策略梯度(deep deterministic po ...
- 5.14 汇编语言:仿写Switch选择结构
选择结构,也称为switch语句,是计算机编程中的一种控制结构,用于根据表达式的值选择不同的执行路径.它允许程序根据表达式的值来决定执行哪个代码块,从而实现多分支选择逻辑.switch语句由一个表达式 ...
- 4.8 C++ Boost 应用JSON解析库
property_tree 是 Boost 库中的一个头文件库,用于处理和解析基于 XML.Json 或者 INFO 格式的数据. property_tree 可以提供一个轻量级的.灵活的.基于二叉数 ...
- Celery Worker log 中记录 task_id
import inspect import logging import threading from logging import Logger as Logger, LogRecord from ...
- delphi 里 多用TArray 而不是 array of
今天写代码发现个bug,是delphi 编译器 核心层面的: unit ddx.att; interface uses System.Generics.Collections, System.Rtti ...
- Spring boot项目实战之记录应用访问日志
1.说明 系统上线后往往我们需要知道都有哪些用户访问了应用的那些功能,以便更好的了解用户需求.防止恶意访问等.为此我们需要给应用添加记录访问日志的功能.下面就开始吧: 2.建表 CREATE TABL ...