Ngày 05 f8bet72 tháng 05 năm 2025 - Máy tính
Trong quá trình sử dụng thực tế của Spring Data Neo4j, tôi đã phát hiện một vấn đề: Sau khi cấu hình TransactionManager
tùy chỉnh và chỉ định spring.data.neo4j.database
, hệ thống sẽ báo lỗi. Bài viết này sẽ ghi lại, phân tích và cung cấp giải pháp cho vấn đề này, nhằm giúp đỡ những người gặp phải tình huống tương tự.
Trước khi mô tả chi tiết vấn đề, tôi xin liệt kê các phiên bản Java, Spring Data Neo4j và các phụ thuộc khác được sử dụng:
Java: Liberica JDK 17.0.7
Spring Boot: 3.4.5
Spring Data Neo4j: 7.4.5
Maven: 3.9.2
1. Mô tả vấn đề
Để minh họa rõ ràng hơn về vấn đề, tôi đã tạo một dự án Maven đơn giản với cấu trúc thư mục như sau:
spring-data-neo4j-database-config-demo
├─ src
│ ├─ main
│ │ ├─ java
│ │ │ └─ com.example.demo
│ │ │ ├─ config
│ │ │ │ └─ Neo4jConfig.java
│ │ │ ├─ repository
│ │ │ │ └─ ActorRepository.java
│ │ │ ├─ model
│ │ │ │ └─ Actor.java
│ │ │ └─ DemoApplication.java
│ │ └─ resources
│ │ └─ application.yaml
│ └─ test
│ └─ java
│ └─ com.example.demo
│ └─ repository
│ └─ ActorRepositoryTest.java
└─ pom.xml
Như có thể thấy:
DemoApplication.java
là lớp khởi động ứng dụng.Actor.java
là lớp Model, đại diện cho Node Actor trong Neo4j.ActorRepository.java
mở rộng interfaceNeo4jRepository
, cung cấp chức năng mặc định để thêm, sửa, xóa và truy vấn Actor.Neo4jConfig.java
là lớp cấu hình tùy chỉnh cho Neo4j.ActorRepositoryTest.java
là lớp kiểm thử đơn vị dành choActorRepository
.
Tiếp theo, chúng ta cùng xem qua cấu hình trong file application.yaml
:
spring:data:neo4j:database:testneo4j:uri:bolt://localhost:7687authentication:username:neo4jpassword:neo4j
Cấu hình trên không chỉ xác định thông tin kết nối đến Neo4j mà còn sử dụng spring.data.neo4j.database
để chỉ định tên cơ sở dữ liệu Neo4j cần kết nối.
Sau đây là đoạn mã của Neo4jConfig.java
:
packagecom.example.demo.config;importorg.neo4j.driver.Driver;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;importorg.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;importorg.springframework.transaction.PlatformTransactionManager;importorg.springframework.transaction.annotation.EnableTransactionManagement;@Configuration@EnableTransactionManagement@EnableNeo4jRepositories(basePackages="com.example.demo.repository")publicclass Neo4jConfig {@Bean public PlatformTransactionManager transactionManager(Driver driver) { return Neo4jTransactionManager.with(driver).build(); }}
Từ đoạn mã trên, ta thấy rằng chúng ta đã cấu hình Bean TransactionManager
cho Neo4j.
Khi mọi thứ đã sẵn sàng, nếu chạy kiểm thử đơn vị bằng ActorRepositoryTest.java
đối với các phương thức CRUD của ActorRepository
, hệ thống sẽ xuất hiện lỗi sau:
[ERROR] com.example.demo.repository.ActorRepositoryTest.testSave -- Time elapsed: 1.526 s <<< ERROR!
java.lang.IllegalStateException: Đã có một giao dịch Spring đang diễn ra cho người dùng mặc định của cơ sở dữ liệu mặc định, nhưng bạn yêu cầu người dùng mặc định của 'test'
at org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager.retrieveTransaction(Neo4jTransactionManager.java:244)
...
Lỗi xảy ra tại dòng 244 của lớp Neo4jTransactionManager.java
trong Spring Data Neo4j. Thông điệp lỗi quan trọng nhấn mạnh rằng: “Đã có một giao dịch Spring đang diễn ra cho người dùng mặc định của cơ sở dữ liệu mặc định, nhưng bạn yêu cầu người dùng mặc định của ’test’”.
2. Phân tích nguyên nhân
Kiểm tra mã nguồn của lớp Neo4jTransactionManager.java
trong Spring Data Neo4j và kết hợp với thông tin từ lỗi, ta nhận thấy rằng giá trị trả về bởi getDatabaseSelection()
và getUserSelection()
không khớp nhau.
Tức là dù đã chỉ định cơ sở dữ liệu cần kết nối trong file application.yaml
, nhưng TransactionManager
vẫn nhận giá trị là cơ sở dữ liệu mặc định. Vấn đề có thể nằm ở lớp cấu hình tùy chỉnh Neo4jConfig.java
.
3. Giải pháp
Dựa trên nguyên nhân tiềm năng, chúng ta thử tham khảo tài liệu và chỉnh sửa Neo4jConfig.java
để chỉ định cơ sở dữ liệu cần kết nối khi cấu hình TransactionManager
. Điều này có thể giúp giải quyết vấn đề.
Sau khi chỉnh sửa, đoạn mã mới của Neo4jConfig.java
như sau:
packagecom.example.demo.config;importorg.neo4j.driver.Driver;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.data.neo4j.core.DatabaseSelection;importorg.springframework.data.neo4j.core.DatabaseSelectionProvider;importorg.springframework.data.neo4j.core.Neo4jClient;importorg.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;importorg.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;importorg.springframework.transaction.PlatformTransactionManager;importorg.springframework.transaction.annotation.EnableTransactionManagement;@Configuration@EnableTransactionManagement@EnableNeo4jRepositories(basePackages="com.example.demo.repository")publicclass Neo4jConfig {@Value("${spring.data.neo4j.database}") private String database; @Bean public DatabaseSelectionProvider databaseSelectionProvider() { return () -> DatabaseSelection.byName(database); } @Bean public Neo4jClient neo4jClient(Driver driver, DatabaseSelectionProvider provider) { return Neo4jClient.with(driver).withDatabaseSelectionProvider(provider).build(); } @Bean public PlatformTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider provider) { return Neo4jTransactionManager.with(driver).withDatabaseSelectionProvider(provider).build(); }}
Trong đoạn mã trên, chúng ta đã đọc giá trị của spring.data.neo4j.database
và sử dụng nó để tạo Bean DatabaseSelectionProvider
tùy chỉnh. Sau đó, Bean Neo4jClient
và TransactionManager
đều sử dụng Provider này.
Sau khi áp dụng thay đổi, chạy lại kiểm thử đơn 7win vị bằng game nhà cái tặng tiền cược miễn phí ActorRepositoryTest.java
, không còn lỗi nào xảy ra.
4. Kết luận
Bài viết này đã mô tả, phân tích và đưa ra giải pháp cho vấn đề xảy ra khi cấu hình TransactionManager
tùy chỉnh trong Spring Data Neo4j và chỉ định spring.data.neo4j.database
.
Mã nguồn đầy đủ của ví dụ này đã được đăng tải lên GitHub, mời các bạn theo dõi hoặc Fork.
[1] Spring: FAQ về cách cấu hình tên cơ sở dữ liệu trong Spring Data JPA - [2] GitHub: Lớp Neo4jTransactionManager.java trong Spring Data Neo4j -
#Spring #Java #Neo4j