文章目录
- 简介
- 安装(docker容器)
- 连接数据库
- Neo4j-CQL语句使用
- Neo4j整合SpringBoot
-
- 创建maven项目并引入依赖
- [编写数据库层 PersonRepository](#编写数据库层 PersonRepository)
- [编写 PersonService](#编写 PersonService)
- 编写测试类
- 多标签、多关系、多类型节点使用
简介
Neo4j是一个开源的NoSQL数据库,使用scala和Java开发。
- 是世界上最先进的图数据库之一,提供原生的图数据存储、检索、处理
- 采用属性图模型,极大的完善和丰富图数据模型
- 专属查询语言Cypher,直观、高效

特性

对比
为了解决关系型数据库中表示关系需要创建中间表且查询效率低的问题。思想,每个用户看成一个节点,节点和节点之间是有关系的。
安装(docker容器)
shell
docker run -d -p 7474:7474 -p 7687:7687 --name neo4j -e "NEO4J_AUTH=neo4j/admin123" -v D/dockerv/neo4j/data:/mydata/data -v D/dockerv/neo4j/logs:/mydata/logs -v D/dockerv/neo4j/conf:/var/lib/neo4j/conf -v D/dockerv/neo4j/import:/var/lib/neo4j/import neo4j
连接数据库
- 访问,并输入密码
http://localhost:7474/browser/
- 连接成功
Neo4j-CQL语句使用
Neo4j的Cypher语言是为处理图形数据而创建的,CQL代表Cypher查询语句。
- 是Neo4j图形数据库的查询语句
- 是一种声明式的模糊匹配语句
- 遵循SQL语法
- 简单、人性化、可读性高
()里面的是节点,[]里面的是关系,{}里面的是属性,>表示关系的方向
sql
-- 创建一个数据模型,A与B是朋友,B与C是朋友,但A听说了C,C不知道A
create (A:Person{name:'huathy'})-[:Friend]->
(B:Person{name:'DY'})-[:Friend]->
(C:Person{name:'JJ'}),
(A)-[:Know]->(C)

sql
-- 查询A的朋友,名字叫DY的
match (a)-:[:Friend]->(b)
where b.name = 'DY'
return b

sql
-- 删除标签为Person的
MATCH (p:Person) DETACH DELETE p
-- Deleted 3 nodes, deleted 3 relationships
Neo4j整合SpringBoot
创建maven项目并引入依赖
xml
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.25</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<scope>provided</scope>
</dependency>
</dependencies>
编写数据库层 PersonRepository
java
package com.hx.neo4j.dao;
import com.hx.neo4j.pojo.Person;
import com.hx.neo4j.vo.PersonVo;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.query.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface PersonRepository extends Neo4jRepository<Person, Long> {
@Query("MATCH (p:user)-[:Friend]->(f:user) WHERE p.name = $name RETURN f")
List<Person> findFriendsByName(String name);
@Query("MATCH (p:user)-[:Friend]->(f:user) RETURN p.name as personName, collect(f.name) as friends")
List<PersonVo> listAllFriendRelationships();
}
编写 PersonService
java
package com.hx.neo4j.service;
import com.hx.neo4j.dao.PersonRepository;
import com.hx.neo4j.pojo.Person;
import lombok.RequiredArgsConstructor;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@RequiredArgsConstructor
public class PersonService {
private final PersonRepository personRepository;
private final Neo4jClient neo4jClient;
@Transactional
public void createPersonWithFriend(Person person, Person friend) {
person.setFriends(List.of(friend));
personRepository.save(friend);
// 如果失败,事务会回滚
throw new RuntimeException("test rollback");
}
public List<String> findPersonNamesByCustomLogic() {
return (List<String>) neo4jClient.query("MATCH (p:User) WHERE size((p)-[:Friend]->()) >= 1 RETURN p.name")
.fetchAs(String.class)
.mappedBy((typeSystem, record) -> record.get("p.name").asString())
.all();
}
}
编写测试类
java
package com.hx.neo4j;
import cn.hutool.json.JSONUtil;
import com.hx.neo4j.dao.PersonRepository;
import com.hx.neo4j.pojo.KnowShip;
import com.hx.neo4j.pojo.Person;
import com.hx.neo4j.service.PersonService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Example;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Neo4jApplicationTests {
@Autowired
private PersonRepository personRepository;
@Autowired
private PersonService personService;
/**
* 测试创建用户与关系
*/
@Test
void createUser() {
Person personC = Person.builder().name("JJ").build();
Person personB = Person.builder().name("DY")
.friends(List.of(personC))
.build();
Person personA = Person.builder().name("Huathy")
.age(18)
.friends(List.of(personB)).build();
personA.setKnowshipList(List.of(
KnowShip.builder().person(personC).build()
));
personRepository.saveAll(List.of(personA, personB));
}
/**
* 测试删除
*/
@Test
void deleteUser() {
Person personB = Person.builder().name("DY").build();
Person personA = Person.builder().name("Huathy").build();
personRepository.deleteAll(List.of(personA, personB));
}
/**
* 测试删除所有
*/
@Test
void deleteUserAll() {
personRepository.deleteAll();
}
/**
* 测试查询所有关系
*/
@Test
void listAllFriendRelationships() {
Object maps = personRepository.listAllFriendRelationships();
System.out.println("maps ==> " + JSONUtil.toJsonPrettyStr(maps));
}
/**
* 测试查询用户
*/
@Test
void findUser() {
// 采用Spring Data JPA的Example方式,会自动的返回Friends关系
Example<Person> example = Example.of(Person.builder().name("Huathy").build());
List<Person> all = personRepository.findAll(example);
System.out.println("user ==> " + JSONUtil.toJsonPrettyStr(all));
// 采用手写CQL语句的方式不会返回关系
List<Person> all2 = personRepository.findFriendsByName("Huathy");
System.out.println("user2 ==> " + JSONUtil.toJsonPrettyStr(all2));
}
/**
* 测试事务回滚
*/
@Test
void createPersonWithFriend() {
Person person1 = Person.builder().name("张三").build();
Person person2 = Person.builder().name("李四").build();
personService.createPersonWithFriend(person1,person2);
}
/**
* Neo4JClient 自定义测试
*/
@Test
void findPersonNamesByCustomLogic() {
List<String> list = personService.findPersonNamesByCustomLogic();
System.out.println("list ==> " + JSONUtil.toJsonPrettyStr(list));
}
}
多标签、多关系、多类型节点使用
创建实体类
java
@Node("Company")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Company {
@Id
@GeneratedValue
private Long id;
private String name;
}
@Node("Customer")
@Data
public class Customer extends Person {
private String contactInfo;
@Relationship(type = "BUYS", direction = Relationship.Direction.OUTGOING)
private List<Product> products;
@Relationship(type = "ASSIGNED_EMPLOYEE", direction = Relationship.Direction.INCOMING)
private Employee accountManager; // 反向关系
}
@Node({"Person", "Employee"})
@Data
@Accessors(chain = true)
public class Employee extends Person {
private String position;
@Relationship(type = "WORKS_FOR")
private Company company;
@Relationship(type = "SERVES", direction = Relationship.Direction.OUTGOING)
private List<Customer> customers;
}
@Node("Product")
@Data
public class Product {
@Id
@GeneratedValue
private Long id;
private String name;
}
编写dao数据库层
java
package com.hx.neo4j.dao;
import com.hx.neo4j.pojo.Company;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CompanyRepository extends Neo4jRepository<Company, Long> {
}
@Repository
public interface CustomerRepository extends Neo4jRepository<Customer, Long> {
}
@Repository
public interface EmployeeRepository extends Neo4jRepository<Employee, Long> {
}
@Repository
public interface ProductRepository extends Neo4jRepository<Product, Long> {
}
编写测试用例
java
package com.hx.neo4j;
import cn.hutool.json.JSONUtil;
import com.hx.neo4j.dao.*;
import com.hx.neo4j.pojo.*;
import com.hx.neo4j.service.PersonService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.annotation.Order;
import org.springframework.data.domain.Example;
import java.util.Collections;
import java.util.List;
@SpringBootTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class Neo4jApplicationTests2 {
@Autowired
private ProductRepository productRepository;
@Autowired
private CompanyRepository companyRepository;
@Autowired
private CustomerRepository customerRepository;
@Autowired
private EmployeeRepository employeeRepository;
private static Long employeeId;
private static Long customerId;
/**
* 创建公司
*/
@Test
@Order(1)
public void testCreateCompany() {
Company company = new Company();
company.setName("OpenAI");
Company saved = companyRepository.save(company);
System.out.println(saved.getId());
Assertions.assertNotNull(saved.getId());
}
/**
* 员工入职
*/
@Test
@Order(2)
public void testEmployeeOnboarding() {
Example<Company> companyExample = Example.of(Company.builder()
.name("OpenAI")
.build());
Company company = companyRepository.findOne(companyExample).orElseThrow();
Employee employee = new Employee();
employee.setName("Alice");
employee.setPosition("Engineer");
employee.setCompany(company);
Employee saved = employeeRepository.save(employee);
employeeId = saved.getNodeId();
Assertions.assertNotNull(employeeId);
Assertions.assertEquals("Engineer", saved.getPosition());
}
/**
* 创建客户
*/
@Test
@Order(3)
public void testAddCustomer() {
Customer customer = new Customer();
customer.setName("Bob");
customer.setContactInfo("[email protected]");
Customer saved = customerRepository.save(customer);
customerId = saved.getNodeId();
Assertions.assertNotNull(customerId);
}
/**
* 分配客户给员工
*/
@Test
@Order(4)
public void testAssignCustomerToEmployee() {
Employee employeeParam = new Employee();
employeeParam.setName("Alice");
Employee employee = employeeRepository.findOne(Example.of(employeeParam)).get();
Customer customerParam = new Customer();
customerParam.setName("Bob");
Customer customer = customerRepository.findOne(Example.of(customerParam)).get();
employee.setCustomers(Collections.singletonList(customer));
employeeRepository.save(employee);
Employee updated = employeeRepository.findOne(Example.of(employeeParam)).get();
Assertions.assertFalse(updated.getCustomers().isEmpty());
Assertions.assertEquals("Bob", updated.getCustomers().get(0).getName());
}
/**
* 客户购买产品
*/
@Test
@Order(5)
public void testCreateProductAndCustomerBuy() {
Product product = new Product();
product.setName("GPT Box");
Product savedProduct = productRepository.save(product);
Customer customer = customerRepository.findById(customerId).orElseThrow();
customer.setProducts(Collections.singletonList(savedProduct));
customerRepository.save(customer);
Customer updated = customerRepository.findById(customerId).orElseThrow();
Assertions.assertFalse(updated.getProducts().isEmpty());
Assertions.assertEquals("GPT Box", updated.getProducts().get(0).getName());
}
}