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
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~~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。