Apache TinkerPop 是通用圖計算框架,默認內存存儲不適合生產。本文演示如何通過 blueprints-jpa-graph 擴展,利用 Hibernate/JPA 將頂點、邊、屬性持久化到 MySQL,包含 Maven 依賴、數據庫初始化、Java 代碼增刪改查完整示例。
CREATE DATABASE tinkerpop DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
GRANT ALL PRIVILEGES ON tinkerpop.* TO 'tinkerpop'@'%' IDENTIFIED BY 'tinkerpop';
FLUSH PRIVILEGES;
<repositories>
<repository>
<id>wingnest-repo</id>
<url>https://www.wingnest.com/mvn-repo/</url>
</repository>
</repositories>
<dependencies>
<dependency><groupId>org.apache.tinkerpop</groupId><artifactId>gremlin-core</artifactId><version>3.0.0.M9-incubating</version></dependency>
<dependency><groupId>org.apache.tinkerpop</groupId><artifactId>gremlin-driver</artifactId><version>3.0.0.M9-incubating</version></dependency>
<dependency><groupId>com.tinkerpop.blueprints</groupId><artifactId>blueprints-core</artifactId><version>2.6.0</version></dependency>
<dependency><groupId>com.wingnest.blueprints</groupId><artifactId>blueprints-jpa-graph</artifactId><version>2.5.0_01</version></dependency>
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-core</artifactId><version>4.3.10.Final</version></dependency>
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-entitymanager</artifactId><version>4.3.10.Final</version></dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.35</version></dependency>
</dependencies>
public class TinkerPopMysqlDemo {
private JpaGraph jpaGraph;
@Before
public void setUp() {
Map<String, Object> props = new HashMap<>();
props.put("javax.persistence.jdbc.driver", "com.mysql.jdbc.Driver");
props.put("javax.persistence.jdbc.url", "jdbc:mysql://localhost:3306/tinkerpop?characterEncoding=UTF-8");
props.put("javax.persistence.jdbc.user", "tinkerpop");
props.put("javax.persistence.jdbc.password", "tinkerpop");
jpaGraph = new JpaGraph("HibernateUnit", props); // 持久化單元名需與 persistence.xml 一致
}
@After
public void tearDown() { jpaGraph.shutdown(); }
@Test
public void testCreate() {
Vertex zhangsan = jpaGraph.addVertex(null);
zhangsan.setProperty("name", "zhangsan");
Vertex lisi = jpaGraph.addVertex(null);
lisi.setProperty("name", "lisi");
Vertex wangwu = jpaGraph.addVertex(null);
wangwu.setProperty("name", "wangwu");
// 建立邊: zhangsan --friend--> lisi, wangwu --friend--> lisi
jpaGraph.addEdge(null, zhangsan, lisi, "friend");
jpaGraph.addEdge(null, wangwu, lisi, "friend");
System.out.println("Create finish");
}
@Test
public void testQuery() {
// 查詢所有頂點
for (Vertex v : jpaGraph.getVertices()) {
System.out.println("name: " + v.getProperty("name") + ", id: " + v.getId());
}
// 查詢張三的出向 friend 邊連接的頂點
Vertex zhangsan = jpaGraph.getVertex(1L);
for (Vertex friend : zhangsan.getVertices(Direction.OUT, "friend")) {
System.out.println("Friend: " + friend.getProperty("name") + ", id: " + friend.getId());
}
}
@Test
public void testDelete() {
Vertex lisi = jpaGraph.getVertex(2L);
jpaGraph.removeVertex(lisi); // 級聯刪除關聯邊
testQuery(); // 驗證剩餘數據
}
}
執行後 MySQL 自動建表 (Hibernate hbm2ddl.auto=update):
mysql> SHOW TABLES;
+---------------------+
| Tables_in_tinkerpop |
+---------------------+
| ENTITY |
| INDEX_BASE |
+---------------------+
mysql> SELECT * FROM ENTITY;
+---------------+----+---------+---------+---------+-----------------+--------+------------+-------------------+-------------------+
| DTYPE | id | REMOVED | VERSION | KEYNAME | valueData | LABEL | element_id | incomingVertex_id | outgoingVertex_id |
+---------------+----+---------+---------+---------+-----------------+--------+------------+-------------------+-------------------+
| BpJpaVertex | 1 | 0 | 0 | NULL | NULL | NULL | NULL | NULL | NULL |
| BpJpaVertex | 2 | 0 | 0 | NULL | NULL | NULL | NULL | NULL | NULL |
| BpJpaVertex | 3 | 0 | 0 | NULL | NULL | NULL | NULL | NULL | NULL |
| BpJpaEdge | 4 | 1 | 0 | NULL | NULL | friend | NULL | 2 | 1 |
| BpJpaEdge | 5 | 1 | 0 | NULL | NULL | friend | NULL | 2 | 3 |
| BpJpaProperty | 6 | 0 | 0 | name | [BLOB: lisi] | NULL | 2 | NULL | NULL |
| BpJpaProperty | 7 | 0 | 0 | name | [BLOB: wangwu] | NULL | 3 | NULL | NULL |
| BpJpaProperty | 8 | 0 | 0 | name | [BLOB: zhangsan]| NULL | 1 | NULL | NULL |
+---------------+----+---------+---------+---------+-----------------+--------+------------+-------------------+-------------------+
表結構特點:單表 ENTITY 通過 DTYPE 區分 Vertex/Edge/Property,valueData 為 BLOB 存儲屬性值,外鍵關聯實現圖拓撲。優點是 Schema 固定、遷移簡單;缺點是大圖查詢需多次自關聯 Join,性能不如原生圖數據庫 (Neo4j、JanusGraph)。
圖數據庫核心價值在於「關係即數據」,TinkerPop 提供統一抽象,選型時以業務規模、團隊能力、運維預算為準。