在混合持久化环境中使用Hibernate,意味着使用不同的数据库或存储技术来处理不同的数据持久化需求。例如,可以同时使用关系型数据库(如MySQL)和NoSQL数据库(如MongoDB)。这种方法在CQRS(Command Query Responsibility Segregation)或其他多存储技术架构中非常常见。
下面我们将展示如何在Spring Boot项目中结合Hibernate和MongoDB实现混合持久化。
1. 项目依赖
在pom.xml中添加必要的依赖:
xml
<dependencies>
<!-- Spring Boot Starter Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<!-- HikariCP for Connection Pooling -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Starter Data MongoDB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
</dependencies>
2. 配置数据源和属性
在application.properties中配置MySQL和MongoDB数据源:
properties
# MySQL Database Configuration
spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase
spring.datasource.username=root
spring.datasource.password=rootpassword
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
# MongoDB Configuration
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=myquerydatabase
3. 创建领域模型
使用MySQL的实体类和仓储接口
Order.java
java
import lombok.Data;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Data
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String customerName;
private String customerAddress;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "order_id")
private List<OrderItem> items = new ArrayList<>();
public void addItem(OrderItem item) {
items.add(item);
}
public void removeItem(OrderItem item) {
items.remove(item);
}
// Business logic methods
public double calculateTotalPrice() {
return items.stream().mapToDouble(OrderItem::getTotalPrice).sum();
}
}
OrderItem.java
java
import lombok.Data;
import javax.persistence.*;
@Data
@Entity
@Table(name = "order_items")
public class OrderItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String product;
private int quantity;
private double price;
public double getTotalPrice() {
return quantity * price;
}
}
OrderRepository.java
java
import org.springframework.data.jpa.repository.JpaRepository;
public interface OrderRepository extends JpaRepository<Order, Long> {
}
使用MongoDB的实体类和仓储接口
OrderView.java
java
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Data
@Document(collection = "orders")
public class OrderView {
@Id
private String id;
private String customerName;
private String customerAddress;
private double totalPrice;
}
OrderViewRepository.java
java
import org.springframework.data.mongodb.repository.MongoRepository;
public interface OrderViewRepository extends MongoRepository<OrderView, String> {
}
4. 创建服务层
写操作服务(Command Service)
OrderCommandService.java
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class OrderCommandService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private OrderViewRepository orderViewRepository;
@Transactional
public Order createOrder(Order order) {
Order savedOrder = orderRepository.save(order);
syncOrderView(savedOrder);
return savedOrder;
}
@Transactional
public Order updateOrder(Order order) {
Order updatedOrder = orderRepository.save(order);
syncOrderView(updatedOrder);
return updatedOrder;
}
@Transactional
public void deleteOrder(Long id) {
orderRepository.deleteById(id);
orderViewRepository.deleteById(id.toString());
}
private void syncOrderView(Order order) {
OrderView orderView = new OrderView();
orderView.setId(order.getId().toString());
orderView.setCustomerName(order.getCustomerName());
orderView.setCustomerAddress(order.getCustomerAddress());
orderView.setTotalPrice(order.calculateTotalPrice());
orderViewRepository.save(orderView);
}
}
读操作服务(Query Service)
OrderQueryService.java
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class OrderQueryService {
@Autowired
private OrderViewRepository orderViewRepository;
public List<OrderView> getAllOrders() {
return orderViewRepository.findAll();
}
public Optional<OrderView> getOrderById(String id) {
return orderViewRepository.findById(id);
}
}
5. 创建控制器
写操作控制器(Command Controller)
OrderCommandController.java
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/orders")
public class OrderCommandController {
@Autowired
private OrderCommandService orderCommandService;
@PostMapping
public ResponseEntity<Order> createOrder(@RequestBody CreateOrderRequest request) {
Order order = new Order();
order.setCustomerName(request.getCustomerName());
order.setCustomerAddress(request.getCustomerAddress());
order.getItems().addAll(request.getItems());
Order createdOrder = orderCommandService.createOrder(order);
return ResponseEntity.ok(createdOrder);
}
@PutMapping("/{id}")
public ResponseEntity<Order> updateOrder(@PathVariable Long id, @RequestBody UpdateOrderRequest request) {
Order order = new Order();
order.setId(id);
order.setCustomerName(request.getCustomerName());
order.setCustomerAddress(request.getCustomerAddress());
order.getItems().addAll(request.getItems());
Order updatedOrder = orderCommandService.updateOrder(order);
return ResponseEntity.ok(updatedOrder);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteOrder(@PathVariable Long id) {
orderCommandService.deleteOrder(id);
return ResponseEntity.noContent().build();
}
}
读操作控制器(Query Controller)
OrderQueryController.java
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/order-views")
public class OrderQueryController {
@Autowired
private OrderQueryService orderQueryService;
@GetMapping
public ResponseEntity<List<OrderView>> getAllOrders() {
List<OrderView> orders = orderQueryService.getAllOrders();
return ResponseEntity.ok(orders);
}
@GetMapping("/{id}")
public ResponseEntity<OrderView> getOrderById(@PathVariable String id) {
return orderQueryService.getOrderById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
}
请求对象
CreateOrderRequest.java
java
import lombok.Data;
import java.util.List;
@Data
public class CreateOrderRequest {
private String customerName;
private String customerAddress;
private List<OrderItem> items;
}
UpdateOrderRequest.java
java
import lombok.Data;
import java.util.List;
@Data
public class UpdateOrderRequest {
private String customerName;
private String customerAddress;
private List<OrderItem> items;
}
6. 运行应用
- 启动MySQL :确保你的MySQL数据库运行在
localhost:3306。 - 创建数据库 :创建一个名为
mydatabase的数据库。 - 启动MongoDB :确保MongoDB数据库运行在
localhost:27017。 - 启动Spring Boot应用:运行Spring Boot应用程序。