头图
This article was first published on the Nebula Graph Community public account

I recently noticed that many students have an urgent need for ORM frameworks, and some enthusiastic students have donated their own projects, and the Nebula community is also working on it. The following mainly introduces some of our experience in using MyBatis to operate Nebula Graph, hoping to help you.

MyBatis

Java development students must be familiar with MyBatis. MyBatis is an excellent persistence layer framework that supports custom SQL, stored procedures and advanced mapping, and eliminates almost all JDBC code and the work of setting parameters and getting result sets.

way of realization

Mainly through MyBatis combined with nebula-jdbc to achieve parameter return value mapping and statement execution.

Demo example

See GitHub for the complete code.

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);

Engineering structure

使用 MyBatis 操作 Nebula Graph 的实践-工程结构

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 operation

 @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 and Path operations

The space is limited, please refer to github for details.

Version adaptation

Currently only Nebula version 2.5 is supported, and the support for subsequent versions is still being adapted.

Summarize

advantage

  • Simple to use, eliminating the redundant code that comes with using JDBC or nebula-client.
  • Connections can be managed using a companion connection pool and can be seamlessly integrated with Spring Boot.
  • nGQL is decoupled from code for easy management.
  • A large number of convenient tags eliminate the trouble of code splicing statements.

existing problems

  • For the return value of Vertex (similar to MATCH v RETURN v ), Edge, and no attribute Path, the Interceptor in MyBatis is currently used for interception processing, which can also be used. However, this implementation method does not feel very good and needs to be optimized later.
  • For the case where the return value type is Path with attribute, multi-tag query and GET SUBGRAPH statement, because there may be various types of entities and edges in the returned result, there is no better mapping method that is currently supported.
  • The JDBC driver used in the above example is the version we developed (see https://github.com/DA1Y1/nebula-jdbc for details), the main difference from the community version is the specification of the service address on the URL and some escape characters In the future, it is hoped that these Features can be merged into the community version for unified use.

For the convenience of use, we have also developed a tool like mybatis-generator to generate some basic code and provide basic addition, deletion, modification and inspection functions. Interested students can search for Nebula Generator in IDEA's Plugins to download, see how to use: https://plugins.jetbrains.com/plugin/18026-nebula-generator

Finally, thanks to @DA1Y1 and several other friends for their contributions!


Exchange graph database technology? To join the Nebula exchange group, please fill in your Nebula business card first, and the Nebula assistant will pull you into the group~~


NebulaGraph
169 声望684 粉丝

NebulaGraph:一个开源的分布式图数据库。欢迎来 GitHub 交流:[链接]