Neo4j的开发方式
目录
1 扩展neo4j
1.1 介绍
1.2 存储过程
1.2.1 调用存储过程
1.2.2 内置存储过程
1.2.3 存储过程的maven配置
1.2.4 书写存储过程
2 远程调试
2.1 Idea的远程调试配置
3 APOC
3.1 Apoc:Cypher查询
3.2 apoc.cypher的api学习
3.3 apoc使用触发器
3.3.1 触发器实例-设置连接到节点的属性
3.3.2 实例二-更新标签
3.3.3 在新节点上创建关系
3.3.4 强制要求属性类型
3.4 定时器
3.5 Diff全图、Diff配置、导出配置文件
3.6 Apoc.meta.graph
3.7 虚拟节点和关系
4 Spring-Data-neo4j
4.1 Neo4j Repositories
4.2 查询方法
4.2.1 查询和查找方法
4.2.2 带注解的查询
4.2.3 查找方法名派生的查询
4.2.4 映射查询结果
4.2.5 排序和分页
4.2.6 投影
4.2.7 重塑数据
4.3 事务
4.4 注释实体
Neo4j Java参考
1 扩展neo4j
1.1 介绍
确保在neo4j.conf中禁用-XX:+ TrustFinalNonStaticFields JVM标志。
1.2 存储过程
用户自定义的存储过程通过Java部署到db,从Cypher进行访问。
存储过程用Java编写并编译成jar文件。 可以通过将jar文件放入每个独立服务器或群集服务器上的$ NEO4J_HOME / plugins目录中将它们部署到数据库中。 必须在每台服务器上重新启动数据库以获取新过程。
存储过程是扩展Neo4j的首选方法。 程序的用例示例如下:
提供对Cypher中不可用的功能的访问。
提供对第三方系统的访问。
执行图形全局操作,例如计算连接的组件或查找密集节点。
表达难以用Cypher声明性地表达的程序操作。
1.2.1 调用存储过程
在org.neo4j.examples的包中的名为findDenseNodes的存储过程,定义如下
CALL org.neo4j.examples.findDenseNodes(1000)
1.2.2 内置存储过程
Neo4j本身内置了很多存储过程,可以通过CALL dbms.procedures()来进行展示。
1.2.3 存储过程的maven配置
需要打jar包来调用,下面介绍整体编写、测试和部署neo4j的存储过程。
配置maven文件如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.neo4j.example</groupId><artifactId>procedure-template</artifactId><version>1.0.0-SNAPSHOT</version><packaging>jar</packaging><name>Neo4j Procedure Template</name><description>A template project for building a Neo4j Procedure</description><properties><neo4j.version>3.5.3</neo4j.version></properties>
第一个依赖项部分包括存储过程在运行时使用的存储过程API。scope设置为provided,因为一旦将过程部署到Neo4j实例,此依赖关系由Neo4j提供。 如果将非Neo4j依赖项添加到项目中,则它们的作用域通常应该是compiled的。
<dependency><groupId>org.neo4j</groupId><artifactId>neo4j</artifactId><version>${neo4j.version}</version><scope>provided</scope></dependency>
接下来,添加测试过程所需的依赖项:
Neo4j Harness,一个允许启动轻量级Neo4j实例的实用程序。 它用于启动Neo4j并部署特定的过程,这极大地简化了测试。
Neo4j Java驱动程序,用于发送调用该过程的cypher语句。
JUnit,一个常见的Java测试框架。
<dependency><groupId>org.neo4j.test</groupId><artifactId>neo4j-harness</artifactId><version>${neo4j.version}</version><scope>test</scope></dependency><dependency><groupId>org.neo4j.driver</groupId><artifactId>neo4j-java-driver</artifactId><version>1.7.3</version><scope>test</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency>
最后自己加上maven shade对应的依赖文件。
1.2.4 书写存储过程
所有的存储过程需要被标注为存储过程@procedure
@procedure可以采取三个可选参数
name用于为过程指定与生成的默认名称不同的名称,即class.path.nameOfMethod。如果mode已指定,则还name必须指定。
mode用于声明过程将执行的交互类型。默认mode是READ。可以使用以下模式:
- READ 此过程仅对图形执行读取操作。
- WRITE 此过程将对图形执行读写操作。
- SCHEMA此过程将对模式执行操作,即创建和删除索引和约束。使用此模式的过程能够读取图形数据,但不能写入。
- DBMS此过程将执行系统操作,如用户管理和查询管理。使用此模式的过程无法读取或写入图形数据。
- Eager是一个默认为false的bool类型,如果其被设置为true,那么Cypher计划器在调用存储过程之前,会计划一个额外的eager操作。
如果需要存储过程的上下文所使用的资源相同,则注解为@Context。
2 远程调试
设置远程调试参数:
dbms.jvm.additional=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
加到neo4j对应的conf文件后重新启动。
2.1 Idea的远程调试配置
3 APOC
APOC是Neo4j 3.3版本推出时正式推荐的一个Java存储过程包,里面包含丰富的函数和过程,作为对Cypher所不能提供的复杂图算法和数据操作功能的补充,APOC还具有使用灵活、高性能等优势。
从neo4j3.0开始,引入了用户定义的存储过程的这一概念。简单地说,存储过程:
- 用Java实现
- 可以在neo4j数据库启动时加载,提高查询效率
- 实现用Cypher很难实现的任何功能
APOC was also the first bundled A Package Of Component for Neo4j in 2009.
APOC also stands for "Awesome Procedures On Cypher"
3.1 Apoc:Cypher查询
Call apoc.cypher.*
可以在Cypher里面调用存储过程,然后在过程里面使用Cypher查询。
使用apoc来执行cypher查询的好处:
1. 可以动态构造查询语句
2. 控制查询的执行时间
3. 条件化查询分支when,case
4. 更灵活的查询执行任务控制:批次大小,并行执行,重试等等
3.2 apoc.cypher的api学习
apoc的neighbor方式
match (e:Eth_Port_Test)
call apoc.neighbors.tohop(e,'RELY_ON_TEST>',3) yield node
return node
3.3 apoc使用触发器
触发器的好处在于自动触发而不需要手动执行
CALL apoc.trigger.add(name, statement, selector) yield name, statement, installed
可以使用’createNode’、‘deleteNode’等类似的名称下声明对应的语句,选择器是before、after、rollback返回上一个和新的触发器信息
//删除以前添加的触发器 返回触发器信息
CALL apoc.trigger.remove(name) yield name, statement, installed//删除所有先前添加的触发器,返回触发器信息
CALL apoc.trigger.removeAll() yield name, statement, installed//更新并列出所有已安装的触发器
CALL apoc.trigger.list() yield name, statement, installed//暂停触发器
Call apoc.trigger.pause(name)//恢复暂停触发器
Call apoc.trigger.resume(name)
辅助函数
apoc.trigger.nodesByLabel({assignedLabels/assign edNodeProperties},'Label') |
|
apoc.trigger.propertiesByKey({assigned NodeProperties},'key') //实际适用语句 apoc.trigger.propertiesByKey({assignedNodeProp erties},"surname") |
函数以property-key过滤propertyEntries,以在具有{assignedNode / RelationshipProperties}和{removedNode / RelationshipProperties}的触发器语句中使用。返回[{old,[new],key,node,relationship}] |
3.3.1 触发器实例-设置连接到节点的属性
apoc官方文档的触发器的demo里面存在一个小问题,会引发循环触发,如何避免?
//创建数据集
CREATE (d:Person {name:'Daniel'})
CREATE (l:Person {name:'Mary'})
CREATE (t:Person {name:'Tom'})
CREATE (j:Person {name:'John'})
CREATE (m:Person {name:'Michael'})
CREATE (a:Person {name:'Anne'})
CREATE (l)-[:DAUGHTER_OF]->(d)
CREATE (t)-[:SON_OF]->(d)
CREATE (t)-[:BROTHER]->(j)
CREATE (a)-[:WIFE_OF]->(d)
CREATE (d)-[:SON_OF]->(m)
CREATE (j)-[:SON_OF]->(d)//使用propertiesBykey在surname属性上添加触发器
CALL apoc.trigger.add('setAllConnectedNodes','UNWIND apoc.trigger.propertiesByKey({assignedNodeProperties},"surname") as prop
WITH prop.node as n
MATCH(n)-[]-(a)
SET a.surname = n.surname', {phase:'after'});
//在节点上添加surname属性时,它会添加到所有的连接的节点(但是添加之后又会循环触发,循环触发的体现见APOC Trigger 循环触发,这样的情况如何处理)
要注意的是,这样的情况会引发数据库后台进程阻塞,需要后台重启neo4j实例,来阻止对应的阻塞进程。前端刷新并不生效。仅仅在前端刷新,会阻塞对Person标签类对象的一切操作,包括delete与set。
//修改相应的触发器语句,此时成功执行,不再阻塞,但是在前端显示不会说Set 6 //properties。仅仅显示//Set 1 property,因为其他5个节点的属性是后台触发完成的。CALL apoc.trigger.add('setAllConnectedNodes','UNWIND apoc.trigger.propertiesByKey({assignedNodeProperties},"surname") as prop
WITH prop.node as n
MATCH(n:Person)-[]-(a:Person)
where not exists(a.surname) or n.surname<>a.surname
SET a.surname = n.surname', {phase:'after'});
3.3.2 实例二-更新标签
数据集
CREATE (k:Actor {name:'Keanu Reeves'})
CREATE (l:Actor {name:'Laurence Fishburne'})
CREATE (c:Actor {name:'Carrie-Anne Moss'})
CREATE (m:Movie {title:'Matrix'})
CREATE (k)-[:ACT_IN]->(m)
CREATE (l)-[:ACT_IN]->(m)
CREATE (c)-[:ACT_IN]->(m)
使用apoc.trigger.nodesByLabel来创建触发器,当一个节点的Actor标签被删除了之后,用Person标签更新所有的Actor标签
CALL apoc.trigger.add('updateLabels',"UNWIND apoc.trigger.nodesByLabel({removedLabels},'Actor') AS node
MATCH (n:Actor)
REMOVE n:Actor SET n:Person SET node:Person", {phase:'before'})MATCH(k:Actor {name:'Keanu Reeves'})
REMOVE k:Actor
3.3.3 在新节点上创建关系
//当新节点的标签是actor,name属性是某些特定值时,为这些新节点创建关系。
CALL apoc.trigger.add('create-rel-new-node',"UNWIND {createdNodes} AS n
MATCH (m:Movie {title:'Matrix'})
WHERE n:Actor AND n.name IN ['Keanu Reeves','Laurence Fishburne','Carrie-Anne Moss']
CREATE (n)-[:ACT_IN]->(m)", {phase:'before'})CREATE (k:Actor {name:'Keanu Reeves'})
CREATE (l:Actor {name:'Laurence Fishburne'})
CREATE (c:Actor {name:'Carrie-Anne Moss'})
CREATE (a:Actor {name:'Tom Hanks'})
CREATE (m:Movie {title:'Matrix'})//暂停触发器
Call apoc.trigger.pause(‘’)//恢复之前暂停的触发器
Call apoc.trigger.resume(‘’)
3.3.4 强制要求属性类型
和之前一样,创建before类型的触发器
我们希望所有的reference属性都是string类型
CALL apoc.trigger.add("forceStringType",
"UNWIND apoc.trigger.propertiesByKey({assignedNodeProperties}, 'reference') AS prop
CALL apoc.util.validate(apoc.meta.type(prop) <> 'STRING', 'expected string property type, got %s', [apoc.meta.type(prop)]) RETURN null", {phase:'before'})//验证:
CREATE (a:Node) SET a.reference = 1//触发器的其他例子
CALL apoc.trigger.add('timestamp','UNWIND {createdNodes} AS n SET n.ts = timestamp()');CALL apoc.trigger.add('lowercase','UNWIND {createdNodes} AS n SET n.id = toLower(n.name)');CALL apoc.trigger.add('txInfo', 'UNWIND {createdNodes} AS n SET n.txId = {transactionId}, n.txTime = {commitTime}', {phase:'after'});CALL apoc.trigger.add('count-removed-rels','MATCH (c:Counter) SET c.count = c.count + size([r IN {deletedRelationships} WHERE type(r) = "X"])')CALL apoc.trigger.add('lowercase-by-label','UNWIND apoc.trigger.nodesByLabel({assignedLabels},'Person') AS n SET n.id = toLower(n.name)')
触发器的参数列表
声明 |
描述 |
transactionId |
返回事务的id |
commitTime |
以毫秒为单位返回事务日期 |
createdNodes |
创建节点时,触发器触发(节点列表) |
createdRelationships |
当创建一个关系时,我们的触发器会触发(关系列表) |
deletedNodes |
当一个节点被驱逐时,我们的触发器会触发(节点列表) |
deletedRelationships |
当关系降低时,我们的触发器会触发(关系列表) |
removedLabels |
当一个标签被删除时,我们的触发器会触发(标签映射到节点列表) |
removedNodeProperties |
当删除节点的属性时,我们的触发器触发(键映射到键,旧,节点的映射列表) |
removedRelationshipProperties |
当删除关系的属性时,我们的触发器触发(键映射到键,旧,关系的映射列表) |
assignedLabels |
当一个labes被分配时我们的触发器触发(标签到节点列表的映射) |
assignedNodeProperties |
当分配节点属性时,我们的触发器触发(键映射到key,old,new,node的映射列表) |
assignedRelationshipProperties |
当关系属性被分配时,我们的触发器触发(键的映射列表,键,旧,新,关系) |
3.4 定时器
3.5 Diff全图、Diff配置、导出配置文件
3.6 Apoc.meta.graph
快速理清各种标签的节点之间的关系
3.7 虚拟节点和关系
图中并不实际存在虚拟节点和关系,它们仅返回给UI以表示图的投影。存在负id。
具体的实例:
1. 将关系聚合为一个
2. 将中间节点折叠成虚拟关系,出于安全考虑隐藏属性或者中间节点/关系。
3. 只返回节点/rels的几个属性到可视化,例如你有巨大的文本属性。
4. 对图算法找到的聚类进行可视化。
5. 将信息聚合到更高的抽象层次。
6. 跳过较长路径的中的中间节点,
7. 图表分组。
8. 将来自其他来源的数据csv、xml、json的数据可视化为图形,甚至不存储它。
9. 投射部分数据。
要记住的一件事是:由于您无法从图中查找已创建的虚拟节点,因此必须将它们保存在您自己的查找结构中。适合它的东西是apoc.map.groupBy从实体列表创建一个映射,由给定属性的字符串值键入。
到目前为止,虚拟实体可以在所有表面上工作,Neo4j-Browser,Bloom,neovis以及所有驱动程序,即使它最初并非如此,它们也非常酷。
它们主要用于可视化,但Cypher本身无法访问它们(它们的ID,标签,类型,属性)。这就是为什么我们添加了许多函数来访问它们的属性,标签和rel-types。
在某些将来,它们可能会被图形视图所包含,能够在Cypher 10中返回图形和可组合的Cypher查询。
4 Spring-Data-neo4j
Neo4j的原生api的抽象层次较低,使用起来不是很方便,原生api的代码要复杂不少,而使用Spring data的则简洁很多。
4.1 Neo4j Repositories
Neo4j repository本身与继承它的repository,它们的实例都已经被Spring自动创建,即意味着我只需要声明接口的引用,而不需要把它和具体的对象相关联,即我们不需要进行实例化的操作。Spring在检测到引用之后已经自动创建对应的实例,我们也不需要为声明的接口方法提供实现。
提供存储库的推荐方法是为每个聚合根定义存储库接口,而不是为每个域类定义存储库接口。底层Spring存储库基础结构将自动检测这些存储库以及其他实现类,并创建可在服务或其他Spring bean中使用的可注入存储库实现。
Spring Data Neo4j提供的存储库构建在Spring Data Commons中的可组合存储库基础结构上。这些允许基于接口的存储库组合,包括为某些接口提供的默认实现和其他方法的其他自定义实现。
Spring Data Neo4j带有一个org.springframework.data.repository.PagingAndSortingRepository专门Neo4jRepository<T. ID>用于所有对象图映射存储库的特殊化。此子接口还添加了特定的finder方法,这些方法采用深度参数来控制获取和保存相关实体的范围。通常,它提供所有期望的存储库方法。如果需要其他操作,则应将其他存储库接口添加到单个接口声明中。
4.2 查询方法
4.2.1 查询和查找方法
您通常在存储库上触发的大多数数据访问操作都将导致对Neo4j数据库执行查询。定义这样的查询只需要在存储库接口上声明一个方法。
public interface PersonRepository extends PagingAndSortingRepository<Person, String> {List<Person> findByLastname(String lastname); Page<Person> findByFirstname(String firstname, Pageable pageable);Person findByShippingAddresses(Address address); Stream<Person> findAllBy();
}
1、该方法显示具有给定姓氏的所有人的查询。将派生查询解析可以与And和连接的约束的方法名称Or。因此,方法名称将导致查询表达式为{"lastname" : lastname}。
2、将分页应用于查询。只需为方法签名配备一个Pageable参数,让方法返回一个Page实例,我们将自动相应地分页查询。
3、显示您可以基于非基本类型的属性进行查询。
4、使用Java 8 Stream,它在迭代流时读取和转换单个元素。
4.2.2 带注解的查询
可以使用@Query注释提供使用Cypher图形查询语言的查询。
这意味着注释的存储库方法
@Query("MATCH (:Actor {name:{name}})-[:ACTED_IN]->(m:Movie) return m")
将使用提供的查询从Neo4j中检索数据。
命名或索引参数{param}将由实际方法参数替换。节点和关系实体直接处理并转换为它们各自的ID。所有其他参数类型被直接提供(即String,Long等)。
注意:
自定义查询不支持自定义深度。此外,@Query不支持将路径映射到域实体,因此,不应从Cypher查询返回路径。相反,返回节点和关系以将它们映射到域实体。
使用@Query放置在存储库方法上的Cypher查询示例,其中值用方法参数替换,如“ 注释查询”部分所述。
public interface MovieRepository extends Neo4jRepository<Movie, Long> {// returns the node with id equal to idOfMovie parameter@Query("MATCH (n) WHERE id(n)={0} RETURN n")Movie getMovieFromId(Integer idOfMovie);// returns the nodes which have a title according to the movieTitle parameter@Query("MATCH (movie:Movie {title={0}}) RETURN movie")Movie getMovieFromTitle(String movieTitle);// same with optional result@Query("MATCH (movie:Movie {title={0}}) RETURN movie")Optional<Movie> getMovieFromTitle(String movieTitle);// returns a Page of Actors that have a ACTS_IN relationship to the movie node with the title equal to movieTitle parameter.@Query(value = "MATCH (movie:Movie {title={0}})<-[:ACTS_IN]-(actor) RETURN actor", countQuery= "MATCH (movie:Movie {title={0}})<-[:ACTS_IN]-(actor) RETURN count(actor)")Page<Actor> getActorsThatActInMovieFromTitle(String movieTitle, PageRequest page);// returns a Page of Actors that have a ACTS_IN relationship to the movie node with the title equal to movieTitle parameter with an accurate total count@Query(value = "MATCH (movie:Movie {title={0}})<-[:ACTS_IN]-(actor) RETURN actor", countQuery = "MATCH (movie:Movie {title={0}})<-[:ACTS_IN]-(actor) RETURN count(*)")Page<Actor> getActorsThatActInMovieFromTitle(String movieTitle, Pageable page);// returns a Slice of Actors that have a ACTS_IN relationship to the movie node with the title equal to movieTitle parameter.@Query("MATCH (movie:Movie {title={0}})<-[:ACTS_IN]-(actor) RETURN actor")Slice<Actor> getActorsThatActInMovieFromTitle(String movieTitle, Pageable page);// returns users who rated a movie (movie parameter) higher than rating (rating parameter)@Query("MATCH (movie:Movie)<-[r:RATED]-(user) " +"WHERE id(movie)={movieId} AND r.stars > {rating} " +"RETURN user")Iterable<User> getUsersWhoRatedMovieFromTitle(@Param("movieId") Movie movie, @Param("rating") Integer rating);// returns users who rated a movie based on movie title (movieTitle parameter) higher than rating (rating parameter)@Query("MATCH (movie:Movie {title:{0}})<-[r:RATED]-(user) " +"WHERE r.stars > {1} " +"RETURN user")Iterable<User> getUsersWhoRatedMovieFromTitle(String movieTitle, Integer rating);@Query(value = "MATCH (movie:Movie) RETURN movie;")Stream<Movie> getAllMovies();}
4.2.3 查找方法名派生的查询
使用底层对象 - 图形映射器中的元数据基础结构,可以将查找器方法名称拆分为其语义部分并转换为Cypher查询。沿关系的导航将反映在生成的MATCH子句中,并且具有运算符的属性将最终作为WHERE子句中的表达式。参数将按它们在方法签名中出现的顺序使用,因此它们应与方法名称中指定的表达式对齐。这里的意思是SDN(Spring-Data-Neo4j)的框架,在Repository接口中可以自动为我们按照某种格式定义的方法补全方法体,避免了我们造轮子的行为,我们只需要声明一个方法名就可以了。
public interface PersonRepository extends Neo4jRepository<Person, Long> {// MATCH (person:Person {name={0}}) RETURN personPerson findByName(String name);// MATCH (person:Person)// WHERE person.age = {0} AND person.married = {1}// RETURN personIterable<Person> findByAgeAndMarried(int age, boolean married);// MATCH (person:Person)// WHERE person.age = {0}// RETURN person ORDER BY person.name SKIP {skip} LIMIT {limit}Page<Person> findByAge(int age, Pageable pageable);// MATCH (person:Person)// WHERE person.age = {0}// RETURN person ORDER BY person.nameList<Person> findByAge(int age, Sort sort);// Allow a custom depth as a parameterPerson findByName(String name, @Depth int depth);// Set a fix depth of 0 for the query@Depth(value = 0)Person findBySurname(String surname);
}
4.2.4 映射查询结果
将复杂的Cypher查询结果转换为自定义的Java对象。
对于通过@Query存储库方法执行的查询,可以指定将复杂查询结果转换为POJO。然后使用查询结果数据填充这些结果对象。这些POJO更易于处理,并且可以用作数据传输对象(DTO),因为它们不附加到Session任何生命周期并且不参与任何生命周期。要利用此功能,请使用带注释的类@QueryResult作为方法返回类型。
public interface MovieRepository extends Neo4jRepository<Movie, Long> {@Query("MATCH (movie:Movie)-[r:RATING]->(), (movie)<-[:ACTS_IN]-(actor:Actor) " +"WHERE movie.id={0} " +"RETURN movie as movie, COLLECT(actor) AS cast, AVG(r.stars) AS averageRating")MovieData getMovieData(String movieId);
}@QueryResult
public class MovieData {Movie movie;Double averageRating;Set<Actor> cast;
}
4.2.5 排序和分页
Spring Data Neo4j支持在使用Spring Data Pageable和Sort接口时对结果进行排序和分页。
//基于repository的分页
Pageable pageable = PageRequest.of(0, 3);
Page<World> page = worldRepository.findAll(pageable, 0);//基于repository的排序
Sort sort = new Sort(Sort.Direction.ASC, "name");
Iterable<World> worlds = worldRepository.findAll(sort, 0)) {//基于repository的分页排序
Pageable pageable = PageRequest.of(0, 3, Sort.Direction.ASC, "name");
Page<World> page = worldRepository.findAll(pageable, 0);
4.2.6 投影
Spring Data Repositories通常在使用查询方法时返回域模型(作为@NodeEntity或作为a @QueryResult)。但是,有时您可能出于各种原因需要该模型的不同视图。在本节中,您将学习如何定义投影以提供简化和简化的资源视图。
查看以下域模型:
@NodeEntity
public class Cinema [w1] {private Long id;private String name, location;@Relationship(type = "VISITED", direction = Relationship.INCOMING)private Set<User> visited = new HashSet<>();@Relationship(type = "BLOCKBUSTER", direction = Relationship.OUTGOING)private Movie blockbusterOfTheWeek;…}
这Cinema有几个属性:
- id 是图id
- name与location是数据属性
- visited与blockbusterOfTheWeek是指向其他域对象的链接
现在假设我们按如下方式创建相应的存储库:
public interface CinemaRepository extends Neo4jRepository<Cinema, Long> {Cinema findByName(String name);
}
Spring Data将返回域对象,包括其所有属性以及访问此影院的所有用户。这可能是大量数据,可能导致性能问题。
有如下几种方法可以避免findByName的问题
- 使用自定义depth进行加载
- 使用自定义带注解的@Query
- 使用投影
简单投影
public interface CinemaNameAndBlockbuster { public String getName();public Movie getBlockbusterOfTheWeek();
}
此投影具有以下详细信息:
一个普通的Java接口,使其具有声明性。
仅导出实体的某些属性。
该CinemaNameAndBlockbuster投影仅具有name和blockbusterOfTheWeek的getter方法,意味着它不会提供之前域实体的用户信息,在这种情况下,查询方法定义返回CinemaNameAndBlockbuster而不是Cinema。
interface CinemaRepository extends Neo4jRepository<Cinema, Long> {CinemaNameAndBlockbuster findByName(String name);
}
投影声明了基础类型与公开属性相关的方法签名之间的规则。因此,需要根据基础类型的属性名称来命名getter方法为getName,否则Spring Data无法查找对应的源属性。这种类型的投影也称为闭合投影
4.2.7 重塑数据
到目前为止,您已经了解了如何使用投影来减少呈现给用户的信息。投影可用于调整公开的数据模型。您可以为投影添加虚拟属性。请看以下投影界面:
interface RenamedProperty { @Value("#{target.name}")String getCinemaName(); @Value("#{target.blockbusterOfTheWeek.name}")String getBlockbusterOfTheWeekName();
}
此投影具有以下详细信息:
- 一个普通的Java接口,使其具有声明性。
- 将name属性公开为名为的虚拟属性cinemaName。
- name将链接Movie实体的子属性导出为虚拟属性。
interface RenamedProperty {@Value("#{target.name} #{(target.location == null) ? '' : target.location}")String getNameAndLocation();
}
在此示例中,仅当影院名称可用时,才会将该位置附加到影院名称。
4.3 事务
Neo4j是一个事务型数据库,只允许在事务内执行操作。Spring Data Neo4j通过@Transaction支持声明式事务,利用TransactionTemplate支持手动事务处理。
其目的是为非CRUD操作定义事务边界
4.4 注释实体
关于JSON序列化的注释
查看上面给出的示例,可以很容易地发现节点和富关系之间对类级别的循环依赖性。只要不序列化对象,它就不会对您的应用程序产生任何影响。今天使用的一种序列化是使用Jackson映射器的JSON序列化。如果数据在SpringBoot或JavaEE等框架中导出,则将使用此映射器库。遍历对象树时,它会在访问Role后访问一个部分Actor。显然它会找到Actor对象并再次访问它,依此类推。这将最终成为一个StackOverflowError。要打破此解析周期,必须通过为类提供注释来支持映射器。这可以通过添加其中之一来完成@JsonIgnore在导致循环或属性的属性上@JsonIgnoreProperties。
参考:
htps://blog.csdn.net/GraphWay/article/details/78957415
Neo4j的开发方式相关推荐
- NEO4J实战之《阿丽塔战斗天使》
欢迎关注作者博客 简书传送门 文章目录 前言 1.1 图数据库介绍 1.2 Neo4j介绍 1.3 Neo4j安装与基本操控 1.3.1 Neo4j的安装部署 1.3.1.1 Neo4j的版本分类 1 ...
- centos 7.4 上安装neo4j并测试
安装 neo4j 社区地址如下: https://neo4j.com/download-center/#community 在centos上的安装过程如下(使用root权限): 获取官方的key cd ...
- NOSQL图形数据库 - Neo4j
Neo4j入门指南 1.简介 2.特点 3.安装 4.基础操作 5.Java集成 5.1 内嵌数据库集成方式 5.2 服务器集成方式 5.3 Spring集成方式 参考文档 1.简介 Neo4j是一个 ...
- 图形数据库Neo4j基本了解
在深入学习图形数据库之前,首先理解属性图的基本概念.一个属性图是由顶点(Vertex),边(Edge),标签(Lable),关系类型和属性(Property)组成的有向图.顶点也称作节点(Node), ...
- linux如何安装neo4j,Ubuntu16.04 如何安装neo4j数据库
什么是neo4j数据库? neo4j数据库是图数据库的一种,属于nosql的一种,常见的nosql数据库还有redis.memcached.mongDB等,不同于传统的关系型数据库,nosql数据也有 ...
- Neo4j - CQL简介
CQL代表Cypher查询语言. 像Oracle数据库具有查询语言SQL,Neo4j具有CQL作为查询语言. Neo4j CQL - 它是Neo4j图形数据库的查询语言. 它是一种声明性模式匹配语言 ...
- 如何用Neo4j和Scikit-Learn做机器学习任务?| 附超详细分步教程
作者 | Mark Needham 译者 | Tianyu.Shawnice 编辑 | Jane 出品 | AI科技大本营(ID:rgznai100) 图算法不是一个新兴技术领域,在开源库中已经有很多 ...
- 最全 Neo4j 可视化图形数据库的工具!
图形可视化工具的类别 在我们深入研究工具之前,了解现有工具的类别很重要.所有可视化工具包都是根据特定目的构建的,因此您必须确保工具的目的符合您的需要. 我将所有图形可视化工具分为四大类: 开发工具,帮 ...
- neo4j安装_SpringBoot使用Neo4j
1.Neo4j简介 Neo4j是一个高性能的,NOSQL图形数据库,它将结构化数据存储在网络上而不是表中.它是一个嵌入式的.基于磁盘的.具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在 ...
- c++ 调用labview_LabVIEW面向对象编程_初窥门径(5):开发方式漫谈
开发软件最少需要三种不同立场的角色来共同协作完成:客户.开发人员和测试人员. 一般来说,通常是由客户方(产品负责人或者是需求分析师)来决定需求,制定需求分析报告.开发验收测试和设定将要开发功能的优先级 ...
最新文章
- webcdn故障处理一例
- c 取地址 虚拟地址 物理地址_通过linux0.11源码理解进程的虚拟地址、线性地址、物理地址...
- 磨刀——python及相关工具
- 怎么选择数据服务器?请记住这五条
- java web项目目录报错_netdevgirl.通过maven创建javaweb项目
- Microsoft SQL Server 2008技术内幕:T-SQL查询---------查询优化
- 排序之插入排序:直接插入+希尔排序
- php imagemagick 漏洞,ImageMagick漏洞(CVE-2016-3714)修复方案
- angular1.x 中重要指令介绍($eval,$parse和$compile)
- throw和throws的区别是什么简答_Throws的作用是 ( )_学小易找答案...
- itest(爱测试) 3.3.7 发布,开源BUG 跟踪管理 敏捷测试管理软件
- 计算机软考网络工程师,软考之网络工程师总结
- 怎么用html实现QQ代挂功能,QQ等级每天有几种加速方式
- java 二叉树详解 + 实现代码
- 外卖和快递行业数据_白领市场三分天下,外卖行业将何去何从?
- 两个椭圆的公切线求法(Matlab)
- 首尾相连数组的最大子数组和
- Problem H. 小凡与英雄救美
- H3C 无线交换机的数据转发原理
- uni-app H5使用web-view父子之间的相互传值