乐趣区

关于数据库:使用-MyBatis-操作-Nebula-Graph-的实践

本文首发于 Nebula Graph Community 公众号

我最近留神到很多同学对于 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/nebu…),与社区版的次要区别在 URL 上服务地址的指定以及⼀些转义字符的解决,后续也心愿能将这些 Feature 合并到社区版本中,统⼀使⽤。

为了方便使用咱们还开发了相似 mybatis-generator 这种工具来生成一些根底代码,提供根本的增删改查性能。感兴趣的同学能够在 IDEA 的 Plugins 中搜寻 Nebula Generator 下载,应用形式参见:https://plugins.jetbrains.com/plugin/18026-nebula-generator

最初感激 @DA1Y1 以及其余几位小伙伴的奉献!


交换图数据库技术?退出 Nebula 交换群请先填写下你的 Nebula 名片,Nebula 小助手会拉你进群~~

退出移动版