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
        
相关推荐
abcnull8 分钟前
用javaparser做精准测试
java·ast·静态代码分析·精准测试·javaparser
wapicn9912 分钟前
微服务架构下的数据核验设计,API接入最佳实践
微服务·云原生·架构
叶小鸡14 分钟前
Java 篇-项目实战-苍穹外卖-笔记汇总
java·开发语言·笔记
AI人工智能+电脑小能手29 分钟前
【大白话说Java面试题】【Java基础篇】第22题:HashMap 和 HashSet 有哪些区别
java·开发语言·哈希算法·散列表·hash
juniperhan44 分钟前
Flink 系列第21篇:Flink SQL 函数与 UDF 全解读:类型推导、开发要点与 Module 扩展
java·大数据·数据仓库·分布式·sql·flink
ID_180079054731 小时前
Python 实现亚马逊商品详情 API 数据准确性校验(极简可用 + JSON 参考)
java·python·json
Ghost Face...1 小时前
龙芯2K1000 SoC启动全流程与架构解析
架构
c++之路1 小时前
C++23概述
java·c++·c++23
侠客工坊1 小时前
移动端 RPA 的架构重构:基于侠客工坊多模态视觉大模型的自动化调度系统压测复盘
人工智能·智能手机·重构·架构·rpa·数字员工·侠客工坊
专注API从业者2 小时前
Open Claw 京东商品监控选品实战:一键抓取、实时监控、高效选品
java·服务器·数据库