Neo4j学习笔记九【Spring Data Neo4j】
到目前为止,我们一直在直接使用Neo4j提供的核心Api爱来访问数据库,尽管这种方法的功能强大且极其灵活,但是底层Neo4j Api的操作有时非常繁琐。下面我们学习下Spring Data Neo4j(SDN),这是一个以更简单、更熟悉为目标的基于Spring开发模型的Spring Data项目中的子项目。
SDN适合做什么以及不适合做什么
SDN从本质上给需要或期待操作基于POJO的域实体的开发者提供了一种方便的使用代码或库函数的方法。如果是早已使用Spring,或早已经在使用丰富领域模型并想映射到一个图形数据库,SDN正适合做这样的工作。
SDN不适合一次处理任意类型的大量数据场景。要加载或存储的任何逻辑在一次操作中超过10000个单元对SDN来说不是一个好的选择。另外,通过提供一个间接层,SDN会比仅仅使用核心Api慢,因此,如果速度和性能时考虑的最重要因素的话,最好还是使用其本身的Api。SDN提供了访问底层GraphDatabaseService实例的代码,可以使用底层核心Api来获得最佳的性能和最大的灵活性。
搭建环境
查看Spring Boot官网,目前最新版1.4(SNAPSHOP)已经包含了Neo4j,但是我们还是使用最新的RELEASE版1.3.6。SDN使用最新版的4.1.2.RELEASE。
1、新建maven项目,pom文件中引入Spring Boot 1.3.6.RELEASE,Spring Boot这里就不多说了,基本上Java码农标配。
2、添加spring-data-neo4j 4.1.2.RELEASE的依赖
下面列出pom文件内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
<?xml version="1.0" encoding="UTF-8"?>
<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.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.didadu</groupId>
<artifactId>springboot_sdn</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.6.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<lombok.version>1.16.2</lombok.version>
<spring-data-neo4j.version>4.1.2.RELEASE</spring-data-neo4j.version>
<guava.version>19.0</guava.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId></dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- spring-data-commons版本有冲突,要升级 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
<version>${spring-data-neo4j.version}</version>
<exclusions>
<exclusion>
<artifactId>spring-data-commons</artifactId>
<groupId>org.springframework.data</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>1.12.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
|
3、配置spring-data-neo4j
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/**
* 新建类Neo4jConfig,用于初始化Neo4j连接
*/
package cn.didadu.config;
//启动类的@SpringBootApplication会自动扫描同级包以及子包,所以下面的@ComponentScan不加应该没关系
//@ComponentScan("cn.didadu.sdn")
"cn.didadu.sdn.repository")
4jRepositories(
public
class Neo4jConfig extends Neo4jConfiguration {
public org.neo4j.ogm.config.
Configuration getConfiguration() {
org.neo4j.ogm.config.Configuration config =
new org.neo4j.ogm.config.Configuration();
config.driverConfiguration()
.setDriverClassName(
"org.neo4j.ogm.drivers.http.driver.HttpDriver")
.setURI(
"http://neo4j:zhangjing@localhost:7474");
return config;
}
public SessionFactory getSessionFactory() {
/**
* 如果不指定节点映射的java bean路径,保存时会报如下警告,导致无法将节点插入Neo4j中
* ... is not an instance of a persistable class
*/
return
new SessionFactory(getConfiguration(),
"cn.didadu.sdn.entity");
}
}
|
SDN建模
下面我们使用SDN来构造和第二章一模一样的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
#### 1、新建Java Bean与节点映射
```java
package cn.didadu.sdn.entity;
@Data
@NodeEntity(label="USERS")
public class User {
public User(){}
public User(String name){
this.name = name;
}
@GraphId
private Long nodeId;
@Property(name="name")
private String name;
//关系直接定义在节点中
@Relationship(type = "IS_FRIEND_OF", direction=Relationship.OUTGOING)
private List<User> friends;
//使用外部定义的关系
@Relationship(type = "HAS_SEEN")
private List<Seen> hasSeenMovies;
}
@Data
@NodeEntity(label = "MOVIES")
public class Movie {
public Movie(String name){
this.name = name;
}
@GraphId
private Long nodeId;
@Property(name="name")
private String name;
}
@Data
@RelationshipEntity(type="HAS_SEEN")
public class Seen {
public Seen(Integer stars, User startNode, Movie endNode){
this.stars = stars;
this.startNode = startNode;
this.endNode = endNode;
}
@GraphId
private Long id;
@Property
private Integer stars;
@StartNode
private User startNode;
@EndNode
private Movie endNode;
}
|
2、新建Java Bean对应的Repository类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package cn.didadu.sdn.repository;
public
interface UserRepository extends GraphRepository<User>{
"MATCH (user:USERS {name:{name}}) RETURN user")
(
User getUserByName(@Param("name") String name);
}
public
interface MovieRepository extends GraphRepository<Movie> {
}
public
interface SeenRepository extends GraphRepository<Seen> {
}
|
访问和持久化实体
1、编写业务Service类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
package cn.didadu.service;
public
class UserService {
private UserRepository userRepository;
private MovieRepository movieRepository;
private SeenRepository seenRepository;
public void initData(){
/**
* 初始化用户
*/
User user1 =
new User(
"John Johnson");
User user2 =
new User(
"Kate Smith");
User user3 =
new User(
"Jack Jeffries");
/**
* 为用户John添加朋友关系
*/
user1.setFriends(Lists.newArrayList(user2, user3));
/**
* 初始化电影
*/
Movie movie1 =
new Movie(
"Fargo");
Movie movie2 =
new Movie(
"Alien");
Movie movie3 =
new Movie(
"Heat");
/**
* 初始化HAS_SEEN关系
*/
Seen hasSeen1 =
new Seen(
5, user1, movie1);
Seen hasSeen2 =
new Seen(
3, user2, movie3);
Seen hasSeen3 =
new Seen(
6, user2, movie2);
Seen hasSeen4 =
new Seen(
4, user3, movie1);
Seen hasSeen5 =
new Seen(
5, user3, movie2);
/**
* 如果不加
@Transactional,下面每个save都会单独开启事物
*/
userRepository.save(Lists.newArrayList(user1, user2, user3));
movieRepository.save(Lists.newArrayList(movie1, movie2, movie3));
seenRepository.save(Lists.newArrayList(hasSeen1, hasSeen2, hasSeen3, hasSeen4, hasSeen5));
}
public User getUserByName(String name){
return userRepository.getUserByName(name);
}
}
|
1、编写Unit Test
1
2
3
|
//测试前先删除数据
match (user:USERS),(movie:MOVIES)
detach delete user,movie;
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public
class UserServiceTest {
private UserService userService;
/**
* 因为是通过http连接到Neo4j数据库的,所以要预先启动Neo4j:neo4j console
*/
public void testInitData(){
userService.initData();
}
public void testGetUserByName(){
User user = userService.getUserByName(
"John Johnson");
System.out.println(user);
}
}
|
至此我们已经可以通过SDN来操作Neo4j了,在本章节之前都是通过嵌入式的方式访问Neo4j的,只有这一章是通过HTTP访问Neo4j。在本节开头说过SDN提供了访问底层GraphDatabaseService实例的代码,但事实上当前版本的SDN中已经没有GraphDatabaseService相关类了,所以目前看来只能通过HTTP的方式远程访问Neo4j数据库了。什么。。。那么强大的核心api用不了了?这怎么能忍!
转自:http://bboyjing.github.io/2016/07/15/Neo4j学习笔记九【Spring-Data-Neo4j】/