我最近注意到很多同学对于 ORM 框架的需求比较迫切,而且有热心的同学已经捐赠了自己开发的项目,Nebula 社区也在 working on it。下面主要介绍一下我们在使用 MyBatis 操作 Nebula Graph 方面的一些经验,希望能够帮助到大家。
Java 开发的同学想必对 MyBatis 都比较熟悉了。MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射,并且免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
主要通过 MyBatis 结合 nebula-jdbc 来实现参数返回值映射以及语句执行。
完整代码参见 GitHub。
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);
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
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class PlayerDO { /** * vid */ private String id; private String name; private Long age; }
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); }
<?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>
@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")); } }
篇幅有限,详情可以参见github。
目前仅支持了 Nebula 2.5 版本,后续版本的支持还在适配中。
优点
存在的问题
MATCH v RETURN v
)、Edge、无属性 Path 的类型目前采用在 MyBatis 中的 Interceptor 做拦截处理,也能满足使用。但这种实现方式感觉不是很好,后期有待优化。