Hibernate(74)如何在CQRS架构中使用Hibernate?

在CQRS(Command Query Responsibility Segregation)架构中,读操作(Query)和写操作(Command)被分离到不同的模型中。这样可以优化读取和写入的性能,并且允许使用不同的存储技术来实现读取和写入模型。Hibernate通常用于处理写操作,因为它擅长处理复杂的交易和关系数据。

下面我们将展示如何在Spring Boot项目中结合Hibernate实现CQRS架构。

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 (for Query Model) -->
    <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. 配置数据源和Hibernate属性

在application.properties中配置MySQL和MongoDB数据源:

properties 复制代码
# MySQL Database Configuration (Command Model)
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 (Query Model)
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=myquerydatabase

3. 定义写模型(Command Model)

Order.java
java 复制代码
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Data
@Entity
@Table(name = "orders")
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String product;
    private int quantity;
    private double price;
}
OrderRepository.java
java 复制代码
import org.springframework.data.jpa.repository.JpaRepository;

public interface OrderRepository extends JpaRepository<Order, Long> {
}

4. 定义读模型(Query Model)

OrderView.java
java 复制代码
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.annotation.Id;

@Data
@Document(collection = "orders")
public class OrderView {

    @Id
    private String id;
    private String product;
    private int quantity;
    private double price;
}
OrderViewRepository.java
java 复制代码
import org.springframework.data.mongodb.repository.MongoRepository;

public interface OrderViewRepository extends MongoRepository<OrderView, String> {
}

5. 创建服务层

写操作服务(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;

    @Transactional
    public Order createOrder(Order order) {
        return orderRepository.save(order);
    }

    @Transactional
    public Order updateOrder(Order order) {
        return orderRepository.save(order);
    }

    @Transactional
    public void deleteOrder(Long id) {
        orderRepository.deleteById(id);
    }
}
读操作服务(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);
    }
}

6. 创建事件和事件处理器

OrderCreatedEvent.java
java 复制代码
import lombok.Data;
import java.io.Serializable;

@Data
public class OrderCreatedEvent implements Serializable {
    private Long orderId;
    private String product;
    private int quantity;
    private double price;
}
OrderUpdatedEvent.java
java 复制代码
import lombok.Data;
import java.io.Serializable;

@Data
public class OrderUpdatedEvent implements Serializable {
    private Long orderId;
    private String product;
    private int quantity;
    private double price;
}
OrderDeletedEvent.java
java 复制代码
import lombok.Data;
import java.io.Serializable;

@Data
public class OrderDeletedEvent implements Serializable {
    private Long orderId;
}

7. 事件发布器和处理器

事件发布器
EventPublisher.java
java 复制代码
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

@Component
public class EventPublisher {

    private final ApplicationEventPublisher applicationEventPublisher;

    public EventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    public void publish(Object event) {
        applicationEventPublisher.publishEvent(event);
    }
}
事件处理器
OrderEventListener.java
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class OrderEventListener {

    @Autowired
    private OrderViewRepository orderViewRepository;

    @EventListener
    public void handleOrderCreatedEvent(OrderCreatedEvent event) {
        OrderView orderView = new OrderView();
        orderView.setId(event.getOrderId().toString());
        orderView.setProduct(event.getProduct());
        orderView.setQuantity(event.getQuantity());
        orderView.setPrice(event.getPrice());
        orderViewRepository.save(orderView);
    }

    @EventListener
    public void handleOrderUpdatedEvent(OrderUpdatedEvent event) {
        OrderView orderView = orderViewRepository.findById(event.getOrderId().toString()).orElse(new OrderView());
        orderView.setProduct(event.getProduct());
        orderView.setQuantity(event.getQuantity());
        orderView.setPrice(event.getPrice());
        orderViewRepository.save(orderView);
    }

    @EventListener
    public void handleOrderDeletedEvent(OrderDeletedEvent event) {
        orderViewRepository.deleteById(event.getOrderId().toString());
    }
}

8. 修改服务层发布事件

修改写操作服务(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 EventPublisher eventPublisher;

    @Transactional
    public Order createOrder(Order order) {
        Order savedOrder = orderRepository.save(order);
        OrderCreatedEvent event = new OrderCreatedEvent();
        event.setOrderId(savedOrder.getId());
        event.setProduct(savedOrder.getProduct());
        event.setQuantity(savedOrder.getQuantity());
        event.setPrice(savedOrder.getPrice());
        eventPublisher.publish(event);
        return savedOrder;
    }

    @Transactional
    public Order updateOrder(Order order) {
        Order updatedOrder = orderRepository.save(order);
        OrderUpdatedEvent event = new OrderUpdatedEvent();
        event.setOrderId(updatedOrder.getId());
        event.setProduct(updatedOrder.getProduct());
        event.setQuantity(updatedOrder.getQuantity());
        event.setPrice(updatedOrder.getPrice());
        eventPublisher.publish(event);
        return updatedOrder;
    }

    @Transactional
    public void deleteOrder(Long id) {
        orderRepository.deleteById(id);
        OrderDeletedEvent event = new OrderDeletedEvent();
        event.setOrderId(id);
        eventPublisher.publish(event);
    }
}

9. 创建控制器

写操作控制器(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 Order order) {
        Order createdOrder = orderCommandService.createOrder(order);
        return ResponseEntity.ok(createdOrder);
    }

    @PutMapping("/{id}")
    public ResponseEntity<Order> updateOrder(@PathVariable Long id, @RequestBody Order order) {
        order.setId(id); // Ensure the order ID is set correctly
        
相关推荐
微步AICRM6 分钟前
一物一码验真的并发链路设计:码段管理、四级关联与异常判定
后端·架构
国科安芯2 小时前
人在回路中的总线:商业空间站环境控制与生命保障系统CANFD网络的可靠性与功能安全
网络·嵌入式硬件·安全·架构·php·抗辐射
aiks_yuan2 小时前
Java CPU 100% 怎么排查:JDK 11 起 jstack 自带线程 CPU 时间,不用再 top -H 换算十六进制(JDK 8、11、17 实测)
java
一条Go3 小时前
告警指纹:一次故障为什么只产生一条 FIRING 记录
后端·架构·github
王中阳Go3 小时前
你把重试加到 2 次那天,200 条里成功还是 181 条,你回看过吗?
人工智能·后端·架构
Zan3 小时前
Tauri 2 实战:为什么一个可靠的桌面应用,应该由 Rust Host 管理生命周期?
前端·架构·rust
神鹰手哥_起飞版3 小时前
我是怎么管理 Coding Agent 的:把任务交出去,也把结果验回来
人工智能·架构·产品经理
Flynn Liang4 小时前
AiServices 源码级拆解:一个接口如何变成 RAG Agent
java·langchain·源码分析·rag·langchain4j·aiservices
Flynn Liang4 小时前
LangChain4j 1.23 架构全景:Java 大模型应用的 6 层抽象
java·langchain·大模型·rag·ai agent·langchain4j
聪明的笨猪猪5 小时前
实际工程问题:AI生成Redis分布式锁的原子性缺陷导致库存超卖
java·经验分享·面试·ai编程