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

特性

对比
为了解决关系型数据库中表示关系需要创建中间表且查询效率低的问题。思想,每个用户看成一个节点,节点和节点之间是有关系的。


安装(docker容器)
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语法
- 简单、人性化、可读性高

()里面的是节点,[]里面的是关系,{}里面的是属性,>表示关系的方向
-- 创建一个数据模型,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)

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

-- 删除标签为Person的
MATCH (p:Person) DETACH DELETE p
-- Deleted 3 nodes, deleted 3 relationships
Neo4j整合SpringBoot
创建maven项目并引入依赖
<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
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
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;@Transactionalpublic 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();}
}
编写测试类
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 {@Autowiredprivate PersonRepository personRepository;@Autowiredprivate PersonService personService;/*** 测试创建用户与关系*/@Testvoid 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));}/*** 测试删除*/@Testvoid deleteUser() {Person personB = Person.builder().name("DY").build();Person personA = Person.builder().name("Huathy").build();personRepository.deleteAll(List.of(personA, personB));}/*** 测试删除所有*/@Testvoid deleteUserAll() {personRepository.deleteAll();}/*** 测试查询所有关系*/@Testvoid listAllFriendRelationships() {Object maps = personRepository.listAllFriendRelationships();System.out.println("maps ==> " + JSONUtil.toJsonPrettyStr(maps));}/*** 测试查询用户*/@Testvoid 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));}/*** 测试事务回滚*/@Testvoid createPersonWithFriend() {Person person1 = Person.builder().name("张三").build();Person person2 = Person.builder().name("李四").build();personService.createPersonWithFriend(person1,person2);}/*** Neo4JClient 自定义测试*/@Testvoid findPersonNamesByCustomLogic() {List<String> list = personService.findPersonNamesByCustomLogic();System.out.println("list ==> " + JSONUtil.toJsonPrettyStr(list));}}
多标签、多关系、多类型节点使用
创建实体类
@Node("Company")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Company {@Id@GeneratedValueprivate 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@GeneratedValueprivate Long id;private String name;
}
编写dao数据库层
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> {
}
编写测试用例
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 {@Autowiredprivate ProductRepository productRepository;@Autowiredprivate CompanyRepository companyRepository;@Autowiredprivate CustomerRepository customerRepository;@Autowiredprivate 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("bob@example.com");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());}
}
