问题
最近需要了解在Spring中使用Neo4j,这里就简单按照官网教程实践了一波。
Spring Initializr
访问https://start.spring.io/网页,完成工程的初始化:
这里主要依赖了Spring Data Neo4j的库,点击生成按钮获得工程初始化代码即可。
Neo4j Server
按照之前的neo4j的Hello World文章,准备一个neo4j服务器即可。neo4j初始化如下图:
Entity
这里准备一个简单实体,具体代码如下:
package com.example.neo4j.model;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Relationship;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@Node
public class Person {
@Id
@GeneratedValue
private Long id;
private String name;
private Person() {
// Empty constructor required as of Neo4j API 2.0.5
};
public Person(String name) {
this.name = name;
}
/**
* Neo4j doesn't REALLY have bi-directional relationships. It just means when querying
* to ignore the direction of the relationship.
* https://dzone.com/articles/modelling-data-neo4j
*/
@Relationship(type = "TEAMMATE")
public Set<Person> teammates;
public void worksWith(Person person) {
if (teammates == null) {
teammates = new HashSet<>();
}
teammates.add(person);
}
public String toString() {
return this.name + "'s teammates => "
+ Optional.ofNullable(this.teammates).orElse(
Collections.emptySet()).stream()
.map(Person::getName)
.collect(Collectors.toList());
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Repository
package com.example.neo4j.repository;
import com.example.neo4j.model.Person;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import java.util.List;
public interface PersonRepository extends Neo4jRepository<Person, Long> {
Person findByName(String name);
List<Person> findByTeammatesName(String name);
}
application.properties
spring.neo4j.uri=bolt://localhost:7687
spring.neo4j.authentication.username=neo4j
spring.neo4j.authentication.password=neo4j
Neo4jApplication
package com.example.neo4j;
import com.example.neo4j.model.Person;
import com.example.neo4j.repository.PersonRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import java.util.Arrays;
import java.util.List;
@SpringBootApplication
@EnableNeo4jRepositories
public class Neo4jApplication {
private final static Logger log = LoggerFactory.getLogger(Neo4jApplication.class);
public static void main(String[] args) {
SpringApplication.run(Neo4jApplication.class, args);
System.exit(0);
}
@Bean
CommandLineRunner demo(PersonRepository personRepository) {
return args -> {
personRepository.deleteAll();
Person greg = new Person("Greg");
Person roy = new Person("Roy");
Person craig = new Person("Craig");
List<Person> team = Arrays.asList(greg, roy, craig);
log.info("Before linking up with Neo4j...");
team.stream().forEach(person -> log.info("\t" + person.toString()));
personRepository.save(greg);
personRepository.save(roy);
personRepository.save(craig);
greg = personRepository.findByName(greg.getName());
greg.worksWith(roy);
greg.worksWith(craig);
personRepository.save(greg);
roy = personRepository.findByName(roy.getName());
roy.worksWith(craig);
// We already know that roy works with greg
personRepository.save(roy);
// We already know craig works with roy and greg
log.info("Lookup each person by name...");
team.stream().forEach(person -> log.info(
"\t" + personRepository.findByName(person.getName()).toString()));
List<Person> teammates = personRepository.findByTeammatesName(greg.getName());
log.info("The following have Greg as a teammate...");
teammates.stream().forEach(person -> log.info("\t" + person.getName()));
};
}
}
结果
"/Applications/IntelliJ IDEA.app/Contents/jbr/Contents/Home/bin/java" -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dfile.encoding=UTF-8 -classpath /Users/zhangyalin/Documents/Pactera/中科院/src/neo4j/target/classes:/Users/zhangyalin/.m2/repository/org/springframework/boot/spring-boot-starter-data-neo4j/2.6.4/spring-boot-starter-data-neo4j-2.6.4.jar:/Users/zhangyalin/.m2/repository/org/springframework/boot/spring-boot-starter/2.6.4/spring-boot-starter-2.6.4.jar:/Users/zhangyalin/.m2/repository/org/springframework/boot/spring-boot/2.6.4/spring-boot-2.6.4.jar:/Users/zhangyalin/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.6.4/spring-boot-autoconfigure-2.6.4.jar:/Users/zhangyalin/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.6.4/spring-boot-starter-logging-2.6.4.jar:/Users/zhangyalin/.m2/repository/ch/qos/logback/logback-classic/1.2.10/logback-classic-1.2.10.jar:/Users/zhangyalin/.m2/repository/ch/qos/logback/logback-core/1.2.10/logback-core-1.2.10.jar:/Users/zhangyalin/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.17.1/log4j-to-slf4j-2.17.1.jar:/Users/zhangyalin/.m2/repository/org/apache/logging/log4j/log4j-api/2.17.1/log4j-api-2.17.1.jar:/Users/zhangyalin/.m2/repository/org/slf4j/jul-to-slf4j/1.7.36/jul-to-slf4j-1.7.36.jar:/Users/zhangyalin/.m2/repository/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar:/Users/zhangyalin/.m2/repository/org/yaml/snakeyaml/1.29/snakeyaml-1.29.jar:/Users/zhangyalin/.m2/repository/org/springframework/data/spring-data-neo4j/6.2.2/spring-data-neo4j-6.2.2.jar:/Users/zhangyalin/.m2/repository/org/apiguardian/apiguardian-api/1.1.1/apiguardian-api-1.1.1.jar:/Users/zhangyalin/.m2/repository/org/neo4j/neo4j-cypher-dsl/2021.4.2/neo4j-cypher-dsl-2021.4.2.jar:/Users/zhangyalin/.m2/repository/org/neo4j/driver/neo4j-java-driver/4.4.3/neo4j-java-driver-4.4.3.jar:/Users/zhangyalin/.m2/repository/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar:/Users/zhangyalin/.m2/repository/org/springframework/spring-beans/5.3.16/spring-beans-5.3.16.jar:/Users/zhangyalin/.m2/repository/org/springframework/spring-context/5.3.16/spring-context-5.3.16.jar:/Users/zhangyalin/.m2/repository/org/springframework/spring-aop/5.3.16/spring-aop-5.3.16.jar:/Users/zhangyalin/.m2/repository/org/springframework/spring-expression/5.3.16/spring-expression-5.3.16.jar:/Users/zhangyalin/.m2/repository/org/springframework/spring-tx/5.3.16/spring-tx-5.3.16.jar:/Users/zhangyalin/.m2/repository/org/springframework/data/spring-data-commons/2.6.2/spring-data-commons-2.6.2.jar:/Users/zhangyalin/.m2/repository/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar:/Users/zhangyalin/.m2/repository/org/springframework/spring-core/5.3.16/spring-core-5.3.16.jar:/Users/zhangyalin/.m2/repository/org/springframework/spring-jcl/5.3.16/spring-jcl-5.3.16.jar com.example.neo4j.Neo4jApplication
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.6.4)
2022-03-24 10:26:50.795 INFO 41861 --- [ main] com.example.neo4j.Neo4jApplication : Starting Neo4jApplication using Java 11.0.14.1 on zylMBP with PID 41861 (/Users/zhangyalin/Documents/Pactera/中科院/src/neo4j/target/classes started by zhangyalin in /Users/zhangyalin/Documents/Pactera/中科院/src/neo4j)
2022-03-24 10:26:50.797 INFO 41861 --- [ main] com.example.neo4j.Neo4jApplication : No active profile set, falling back to 1 default profile: "default"
2022-03-24 10:26:51.087 INFO 41861 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Neo4j repositories in DEFAULT mode.
2022-03-24 10:26:51.118 INFO 41861 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 26 ms. Found 1 Neo4j repository interfaces.
2022-03-24 10:26:51.367 INFO 41861 --- [ main] org.neo4j.driver.internal.DriverFactory : Direct driver instance 814753967 created for server address localhost:7687
2022-03-24 10:26:51.609 INFO 41861 --- [ main] com.example.neo4j.Neo4jApplication : Started Neo4jApplication in 1.197 seconds (JVM running for 2.772)
2022-03-24 10:26:51.874 INFO 41861 --- [ main] com.example.neo4j.Neo4jApplication : Before linking up with Neo4j...
2022-03-24 10:26:51.875 INFO 41861 --- [ main] com.example.neo4j.Neo4jApplication : Greg's teammates => []
2022-03-24 10:26:51.876 INFO 41861 --- [ main] com.example.neo4j.Neo4jApplication : Roy's teammates => []
2022-03-24 10:26:51.876 INFO 41861 --- [ main] com.example.neo4j.Neo4jApplication : Craig's teammates => []
2022-03-24 10:26:53.012 INFO 41861 --- [ main] com.example.neo4j.Neo4jApplication : Lookup each person by name...
2022-03-24 10:26:53.106 INFO 41861 --- [ main] com.example.neo4j.Neo4jApplication : Greg's teammates => [Roy, Craig]
2022-03-24 10:26:53.138 INFO 41861 --- [ main] com.example.neo4j.Neo4jApplication : Roy's teammates => [Craig]
2022-03-24 10:26:53.163 INFO 41861 --- [ main] com.example.neo4j.Neo4jApplication : Craig's teammates => []
2022-03-24 10:26:53.230 INFO 41861 --- [ main] com.example.neo4j.Neo4jApplication : The following have Greg as a teammate...
2022-03-24 10:26:53.237 INFO 41861 --- [ionShutdownHook] o.neo4j.driver.internal.InternalDriver : Closing driver instance 814753967
2022-03-24 10:26:53.240 INFO 41861 --- [ionShutdownHook] o.n.d.i.async.pool.ConnectionPoolImpl : Closing connection pool towards localhost:7687
Process finished with exit code 0
neo4j中节点情况:
注意一下,neo4j社区版是不能创建自定义数据库的。