什么是SDN
Spring Data Neo4j 簡稱SND,是一個對象-圖形映射(OGM)框架,是為了簡化開發(fā)者的工作而創(chuàng)建的诈铛,它的目的是通過處理所有底層工作和從Neo4j讀域?qū)嶓w并寫回去所必須的映射邏輯來提高效率
缺點
SND從很大程度上為開發(fā)者提供了方便的使用代碼和庫函數(shù),能非常方便的集成與Spring,但是SDN不適合一次處理任意類型的大量數(shù)據(jù)的場景澡屡,要加載或者存儲的任何邏輯在一次操作中超過10000個單元對SDN來說不是一個很好的選擇炼蛤。SDN相當(dāng)于充當(dāng)了一個間接層的妖爷,操作數(shù)量過大的話,相比原生的核心API會慢很多理朋。
SDN建模
假設(shè)現(xiàn)在有兩個節(jié)點流程(Process) and 任務(wù)(Task) 通過關(guān)系(PROCESS_IN)建立兩個節(jié)點的連接絮识,應(yīng)當(dāng)如何建模?
分析在工作流程業(yè)務(wù)中嗽上,** 流程(Process)實例** 與** 任務(wù)(Task)實例** 是一對多的關(guān)系次舌,一個任務(wù)只能有一個流程,一個流程包含多個任務(wù)兽愤。
在SDN中,節(jié)點彼念、關(guān)系 都可以用過注解來表示挪圾,非常方便
** @NodeEntity** 增加該注解屬性在類上,表示這是一個節(jié)點国拇。
** @GraphId ** 該節(jié)點的唯一編號洛史,會自動生成惯殊,跟mysql酱吝、oracle里面的id一個性質(zhì),是必須的土思。
** @Relationship(type = "")** 該屬性增加在節(jié)點的屬性上务热,該屬性必須為節(jié)點,type 表示連接他們的關(guān)系(Relationship)的名字己儒。
** @RelationshipEntity(type = "") ** 該注解增加在類上崎岂,表示他是一個關(guān)系(Relationship) type表示該關(guān)系的名字,不寫則默認類的名字闪湾。
** @StartNode ** 該屬性增加在關(guān)系的屬性上冲甘,該屬性必須為節(jié)點 表示該節(jié)點為起點節(jié)點。
** @EndNode** 該屬性增加在關(guān)系的屬性上途样,該屬性必須為節(jié)點 表示該節(jié)點為結(jié)束節(jié)點江醇。
注意:節(jié)點與節(jié)點的關(guān)系表述,必須要有明確的開始和結(jié)束何暇。
如下圖所示:
流程實例與任務(wù)實例及連接他們的關(guān)系 在代碼中如下:
Process類:
@NodeEntity
public class Process {
@GraphId
private Long id;
@Relationship(type = "PROCESS_IN")
private List<Task> tasks;
private String processName;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<Task> getTasks() {
return tasks;
}
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
}
public String getProcessName() {
return processName;
}
public void setProcessName(String processName) {
this.processName = processName;
}
}
Task類:
@NodeEntity
public class Task {
@GraphId
private Long id;
private String taskName;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
}
關(guān)系(PROCESS_IN)
@RelationshipEntity(type = "PROCESS_IN")
public class ProcessIn {
@GraphId
private Long id;
@StartNode
private Process process;
@EndNode
private Task task;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Process getProcess() {
return process;
}
public void setProcess(Process process) {
this.process = process;
}
public Task getTask() {
return task;
}
public void setTask(Task task) {
this.task = task;
}
}
SDN訪問和持久化實體
SDN提供了一個Neo4jTemplate類陶夜,能用于實例化,可以直接使用或當(dāng)Spring初始化時用于應(yīng)用程序裆站。類似于Spring模板類JDBCTemplate条辟,它提供了很多其他的底層應(yīng)用方法用于操作、查詢以及獲得對節(jié)點和關(guān)系的訪問宏胯。
@Autowired
private Neo4jTemplate neo4jTemplate;
@Transactional
public void saveTask(){
Task task = new Task();
task.setTaskName("測試任務(wù)");
Task save = neo4jTemplate.save(task);
Task load = neo4jTemplate.load(Task.class, save.getId());
System.out.println(load.getTaskName());
}
如上述表示羽嫡,通過@Autowired 注入該類,就可以調(diào)用起操作肩袍、查詢等方法厂僧,實現(xiàn)對數(shù)據(jù)的實例化。但是一般在的真正的業(yè)務(wù)代碼的實現(xiàn)中了牛,用于加載和保存實體一般是通過資源庫模式來實現(xiàn)(簡單來說颜屠,就是用一個知道如何翻譯域?qū)嶓w到或從數(shù)據(jù)倉庫格式替換合適的資源庫實現(xiàn))。
SDN資源庫在某一段時間是專門設(shè)置用于一個域類鹰祸,并針對對應(yīng)的域類提供整個范圍的默認操作甫窟。
SDN提供了Interface GraphRepository<T>接口,自己定義的接口繼承擴展GraphRepository蛙婴,它定義了域類可用的默認操作的最廣集合粗井。Java泛型的使用把他與對應(yīng)的域?qū)嶓w聯(lián)系起來。
public interface TaskRepository extends GraphRepository<Task> {}
GraphRepository接口從實質(zhì)上鞏固的所有的其他接口,因此為Task定義了包括CRUD的操作浇衬、索引和遍歷懒构。該接口比Neo4jTemplate 類高一級,它也是提供許多樣板代碼的實現(xiàn)耘擂,但以更針對域的方式胆剧。
SDN注解查詢
SDN除了提供了一系列的接口查詢外维贺,還提供了更高級的注解查詢炼邀,使用注解@Query用于標識一個執(zhí)行的查詢漫雕。注解可以用于一個節(jié)點的實體的一個字段上性誉,或者知識庫接口中的方法上靶剑。當(dāng)一個節(jié)點實體上的字段被訪問或在一個知識庫接口上調(diào)用一個方式時群凶,查詢被執(zhí)行并且返回結(jié)果柠偶。
@Query注釋可以定義在你自己實現(xiàn)的特定的接口上户秤,下面定義了兩個接口 一個通過名字查詢?nèi)蝿?wù)螺捐,一個則是通過流程實例id查詢相關(guān)的任務(wù)颠悬。查詢可設(shè)置變量,順序默認為接口參數(shù)名字定血。
@Repository
public interface TaskRepository extends GraphRepository<Task> {
@Query("MATCH (t:Task) WHERE t.taskName =~ ('(?i).*'+{taskName}+'.*') RETURN t")
Collection<Task> findByNameContaining(@Param("taskName") String taskName);
@Query("START p = node({id}) MATCH (p:Process)-[r:PROCESS_IN]->(t:Task) RETURN t;")
Collection<Task> findByProcessId(@Param("id") Long id);
}
SDN也能理解相關(guān)的屬性定義赔癌,如果你想通過任務(wù)的名字查詢某個任務(wù),可以定義以下方法糠悼。這里應(yīng)用了屬性的第一部分届榄,如果這個屬性是基于這個任務(wù)類型的,就可以通過任務(wù)的名字進行搜索倔喂。但屬性必須是存在的铝条,不存在啟動會出錯。
@Repository
public interface TaskRepository extends GraphRepository<Task> {
Task findByTaskName(@Param("taskName") String taskName);
}
如果你想有多個屬性并列查詢時席噩,你可以通過And 或者Or將兩個屬性聯(lián)系起來班缰,查詢,參數(shù)則按順序?qū)懭搿?/p>
@Repository
public interface TaskRepository extends GraphRepository<Task> {
Task findByTaskNameAndId(String taskName,Long id);
}
SDN與Spring集成
SDN原來版本集成是通過配置文件來實現(xiàn)悼枢。后期版本通過實現(xiàn)Neo4jConfiguration類 進行注入配置