AWS MySQL 读写分离配置指南

# AWS JDBC Wrapper读写分离配置实战:Spring Boot + MyBatis Plus完整解决方案

## 前言

在微服务架构中,数据库读写分离是提升系统性能的重要手段。本文将详细介绍如何在Spring Boot项目中使用AWS JDBC Wrapper实现自动读写分离,重点解决MyBatis Plus框架下的配置难点,并对比Spring JPA的差异。

**核心结论**:AWS JDBC Wrapper需要连接的`readOnly`状态来判断路由,MyBatis Plus需要手动添加`@Transactional(readOnly = true)`,而Spring JPA会自动处理。

## 一、AWS JDBC Wrapper简介

### 1.1 什么是AWS JDBC Wrapper

AWS JDBC Wrapper是Amazon提供的数据库连接增强工具,支持:

- 自动故障转移

- 读写分离

- 连接池管理

- 性能监控

### 1.2 读写分离原理

```mermaid

graph TD

A[应用程序] --> B[AWS JDBC Wrapper]

B --> C{检查Connection.readOnly}

C -->|true| D[Aurora Reader Endpoint]

C -->|false| E[Aurora Writer Endpoint]

D --> F[只读副本]

E --> G[主库]

```

**关键机制**:AWS JDBC Wrapper通过检测JDBC连接的`readOnly`属性来决定路由目标。

## 二、基础配置

### 2.1 Maven依赖

```xml

<dependency>

<groupId>software.amazon.jdbc</groupId>

<artifactId>aws-advanced-jdbc-wrapper</artifactId>

<version>2.2.0</version>

</dependency>

<dependency>

<groupId>com.baomidou</groupId>

<artifactId>mybatis-plus-boot-starter</artifactId>

<version>3.4.3</version>

</dependency>

```

### 2.2 数据源配置

```yaml

spring:

datasource:

type: com.zaxxer.hikari.HikariDataSource

driver-class-name: software.amazon.jdbc.Driver

username: ${DB_USERNAME}

password: ${DB_PASSWORD}

url: jdbc:aws-wrapper:mysql://${AURORA_CLUSTER_ENDPOINT}:3306/${DATABASE_NAME}?wrapperPlugins=readWriteSplitting,failover&characterEncoding=utf-8&wrapperLogLevel=FINEST&useSSL=true&requireSSL=true

```

**重要参数说明**:

- `wrapperPlugins=readWriteSplitting,failover`:启用读写分离和故障转移

- `wrapperLogLevel=FINEST`:启用详细日志,便于调试

### 2.3 日志配置

```xml

<!-- logback.xml -->

<configuration>

<!-- AWS JDBC Wrapper日志 -->

<logger name="software.amazon.jdbc" level="TRACE"/>

<logger name="software.amazon.jdbc.plugin.readwritesplitting" level="TRACE"/>

<logger name="software.amazon.jdbc.plugin.failover" level="TRACE"/>

<!-- HikariCP连接池日志 -->

<logger name="com.zaxxer.hikari" level="DEBUG"/>

</configuration>

```

## 三、核心问题:MyBatis Plus的读写分离挑战

### 3.1 问题现象

**预期**:查询操作自动路由到只读副本

**实际**:所有操作都路由到主库

**关键日志**:

```

TRACE ReadWriteSplittingPlugin - Writer connection set to 'cluster-endpoint:3306'

```

### 3.2 根本原因分析

**Spring JPA vs MyBatis Plus的差异**:

| 框架 | 事务配置 | readOnly设置 | 读写分离效果 |

|------|----------|--------------|-------------|

| Spring JPA | Repository方法自动添加`@Transactional(readOnly=true)` | ✅ 自动 | ✅ 有效 |

| MyBatis Plus | ServiceImpl无自动事务配置 | ❌ 手动 | ❌ 无效 |

**技术原理**:

1. AWS JDBC Wrapper依赖`Connection.setReadOnly(true)`来判断路由

2. Spring事务管理器负责设置连接的readOnly状态

3. 只有在`@Transactional(readOnly=true)`时,Spring才会调用`connection.setReadOnly(true)`

## 四、解决方案

### 4.1 方案一:Service层添加只读事务(推荐)

```java

@Service

@Slf4j

public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

/**

* 查询方法 - 走读库

*/

@Override

@Transactional(readOnly = true)

public List<User> list(QueryWrapper<User> queryWrapper) {

return super.list(queryWrapper);

}

/**

* 分页查询 - 走读库

*/

@Override

@Transactional(readOnly = true)

public IPage<User> page(IPage<User> page, QueryWrapper<User> queryWrapper) {

return super.page(page, queryWrapper);

}

/**

* 统计查询 - 走读库

*/

@Override

@Transactional(readOnly = true)

public int count(QueryWrapper<User> queryWrapper) {

return super.count(queryWrapper);

}

/**

* 写操作 - 走写库

*/

@Override

@Transactional

public boolean save(User entity) {

return super.save(entity);

}

}

```

### 4.2 方案二:Controller层添加只读事务

```java

@RestController

@RequestMapping("/api/users")

public class UserController {

@Autowired

private IUserService userService;

/**

* 查询接口 - 走读库

*/

@GetMapping("/list")

@Transactional(readOnly = true)

public Result<List<User>> getUserList() {

List<User> users = userService.list();

return Result.success(users);

}

/**

* 创建接口 - 走写库

*/

@PostMapping

@Transactional

public Result<Boolean> createUser(@RequestBody User user) {

boolean success = userService.save(user);

return Result.success(success);

}

}

```

### 4.3 方案三:创建专门的只读Service

```java

@Service

@Transactional(readOnly = true) // 类级别只读事务

public class UserReadOnlyService {

@Autowired

private UserMapper userMapper;

public List<User> queryUsers(QueryWrapper<User> queryWrapper) {

return userMapper.selectList(queryWrapper);

}

public IPage<User> queryUsersPage(IPage<User> page, QueryWrapper<User> queryWrapper) {

return userMapper.selectPage(page, queryWrapper);

}

public long queryCount(QueryWrapper<User> queryWrapper) {

return userMapper.selectCount(queryWrapper);

}

}

```

### 4.4 方案四:混合使用JDBC和MyBatis Plus

```java

@Service

public class UserHybridService {

@Autowired

private DataSource dataSource;

@Autowired

private IUserService userService;

/**

* 简单查询用JDBC - 走读库

*/

public long getUserCount() throws SQLException {

try (Connection conn = dataSource.getConnection()) {

conn.setReadOnly(true);

try (PreparedStatement stmt = conn.prepareStatement("SELECT COUNT(*) FROM user")) {

try (ResultSet rs = stmt.executeQuery()) {

return rs.next() ? rs.getLong(1) : 0;

}

}

}

}

/**

* 复杂操作用MyBatis Plus - 走写库

*/

@Transactional

public boolean createUserWithRelations(User user) {

return userService.save(user);

}

}

```

## 五、验证方法

### 5.1 测试代码

```java

@RestController

@RequestMapping("/api/test")

public class ReadWriteTestController {

@Autowired

private IUserService userService;

@Autowired

private DataSource dataSource;

/**

* 测试JDBC读操作

*/

@GetMapping("/jdbc-read")

public String testJdbcRead() throws SQLException {

try (Connection conn = dataSource.getConnection()) {

conn.setReadOnly(true);

// 执行查询...

return "JDBC读测试完成";

}

}

/**

* 测试MyBatis Plus读操作

*/

@GetMapping("/mybatis-read")

@Transactional(readOnly = true)

public String testMybatisRead() {

userService.list();

return "MyBatis Plus读测试完成";

}

}

```

### 5.2 期望的日志输出

**走读库的日志**:

```

TRACE ReadWriteSplittingPlugin - Reader connection set to 'cluster-ro-endpoint:3306'

TRACE ReadWriteSplittingPlugin - Routing read operation to reader endpoint

```

**走写库的日志**:

```

TRACE ReadWriteSplittingPlugin - Writer connection set to 'cluster-endpoint:3306'

TRACE ReadWriteSplittingPlugin - Routing write operation to writer endpoint

```

## 六、最佳实践

### 6.1 设计原则

1. **查询操作**:统一添加`@Transactional(readOnly = true)`

2. **写操作**:使用`@Transactional`或不添加注解

3. **事务边界**:在Service层或Controller层明确定义

4. **职责分离**:考虑创建专门的只读Service类

### 6.2 实施优先级

**高优先级**:

- 核心业务Service(订单、支付、用户等)

- 高频查询接口

- 报表和统计功能

**中优先级**:

- 基础数据Service

- 管理后台查询

- 定时任务查询

**低优先级**:

- 低频管理功能

- 工具类查询

### 6.3 注意事项

1. **事务传播**:在事务中的所有操作都会走主库

2. **连接复用**:HikariCP可能复用连接,观察日志时注意时间戳

3. **故障转移**:读库不可用时会自动转移到主库

4. **复制延迟**:业务逻辑需要考虑主从复制延迟

## 七、Spring JPA对比

### 7.1 为什么Spring JPA更容易实现读写分离

```java

// Spring Data JPA - 自动只读

@Repository

public interface UserRepository extends JpaRepository<User, Long> {

// 框架自动为查询方法添加 @Transactional(readOnly = true)

List<User> findByStatus(String status); // 自动走读库

// 框架自动为写方法添加 @Transactional

User save(User user); // 自动走写库

}

```

### 7.2 JPA vs MyBatis Plus总结

| 特性 | Spring JPA | MyBatis Plus |

|------|------------|--------------|

| 学习曲线 | 简单,开箱即用 | 需要理解事务配置 |

| 自动化程度 | 高度自动化 | 需要手动配置 |

| 性能控制 | 抽象层较厚 | 更接近原生SQL |

| 读写分离 | 自动支持 | 需要手动实现 |

| SQL优化 | 相对困难 | 灵活度高 |

## 八、故障排查

### 8.1 常见问题

**问题1:看不到ReadWriteSplittingPlugin日志**

- 检查URL中的`wrapperLogLevel=FINEST`

- 确认logback.xml中的日志级别

- 重启应用重新观察

**问题2:所有操作都连接同一endpoint**

- 检查`@Transactional(readOnly = true)`是否正确添加

- 确认Aurora集群是否有只读副本

- 验证URL中的`wrapperPlugins`参数

**问题3:连接失败**

- 检查SSL证书配置

- 验证网络连通性

- 确认Aurora集群状态

### 8.2 调试技巧

1. **启用详细日志**:

```yaml

logging:

level:

software.amazon.jdbc: TRACE

com.zaxxer.hikari: DEBUG

```

2. **诊断连接状态**:

```java

@GetMapping("/diagnose")

public Map<String, Object> diagnoseDatasource() {

try (Connection conn = dataSource.getConnection()) {

DatabaseMetaData metaData = conn.getMetaData();

Map<String, Object> info = new HashMap<>();

info.put("driverName", metaData.getDriverName());

info.put("url", metaData.getURL());

info.put("isAwsWrapper", metaData.getDriverName().contains("Amazon"));

return info;

}

}

```

## 九、总结

AWS JDBC Wrapper是一个强大的数据库连接工具,但在MyBatis Plus环境下需要正确配置事务注解才能实现读写分离。核心要点:

1. **理解原理**:读写分离依赖`Connection.setReadOnly()`状态

2. **正确配置**:为查询方法添加`@Transactional(readOnly = true)`

3. **验证效果**:通过日志确认路由行为

4. **渐进实施**:按优先级逐步改造现有代码

通过本文的配置方案,可以有效提升系统的数据库读性能,减轻主库压力,为系统的高可用和高性能打下坚实基础。

---

> **作者经验**:在实际项目中,建议先在测试环境验证配置,观察日志确认读写分离生效后,再逐步推广到生产环境。同时要注意监控Aurora集群的读写负载分布,确保达到预期的性能提升效果。

**技术栈**:Spring Boot 2.x + MyBatis Plus 3.4.x + AWS JDBC Wrapper 2.2.x + Aurora MySQL

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/87153.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/87153.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

opencv检测运动物体

检测到的所有移动物体中轮廓中找到面积最大的轮廓&#xff0c;并绘制这个轮廓的矩形框。 #include <opencv2/opencv.hpp> #include <iostream>int main() {// 打开视频文件或摄像头cv::VideoCapture capture;capture.open("move3.mp4"); // 打开视频文件…

Camera相机人脸识别系列专题分析之十五:人脸特征检测FFD算法之libcvface_api.so算法API详细注释解析

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: Camera相机人脸识别系列专题分析之十五:人脸特征检测FFD算法之libcvface_api.so算法API详细注释解析 目录 一、libcvface_api.so算法API详细注释解析

图像擦除论文-2:SmartEraser、Erase Diffusion、OmniEraser

图像生成模型应用系列——图像擦除&#xff1a; 图像擦除论文-1&#xff1a;PixelHacker、PowerPanint等 图像擦除论文-2&#xff1a;擦除类型数据集构建(1) Erase Diffusion Erase Diffusion: Empowering Object Removal Through Calibrating Diffusion Pathways https://git…

九识无人车陕西运营中心展厅启幕 打造智能城配物流新标杆

7月1日&#xff0c;九识无人车陕西运营中心展厅正式开业&#xff0c;全国业务版图再添重要一子。这座展厅是九识在陕西省的首家展厅&#xff0c;由九识第一位正式提车的客户、首位代理商伙伴孙朋奇先生打造。展厅集产品展示与技术体验于一体&#xff0c;成为西北地区城配领域自…

AI智能体|扣子(Coze)搭建【沉浸式历史故事解说视频】工作流

主包讲解历史对我们的好处&#xff0c;纯个人观点&#xff01; 这个世界是存在一些规律的&#xff0c;很多东西并不能够通过自己的聪明去创新&#xff0c;去改变的。 无论你怎么样创新&#xff0c;你都会回到哪个规律中去&#xff0c;比如很多人做一些商业模式的创新&#xff0…

Softhub软件下载站实战开发(十):实现图片视频上传下载接口

文章目录 Softhub软件下载站实战开发&#xff08;十&#xff09;&#xff1a;实现图片视频上传下载接口 &#x1f5bc;️&#x1f3a5;系统架构图核心功能设计 &#x1f6e0;️1. 文件上传流程2. 关键技术实现2.1 雪花算法2.2 文件校验机制 ✅2.3 文件去重机制 &#x1f50d;2.…

[JS逆向] 喜马拉雅登录案例 -- 补环境

博客配套代码发布于github&#xff1a;喜马拉雅登录 &#xff08;欢迎顺手Star一下⭐&#xff09; 相关知识点&#xff1a;webpack 补环境 相关爬虫专栏&#xff1a;JS逆向爬虫实战 爬虫知识点合集 爬虫实战案例 逆向知识点合集 此案例目标为逆向成功对应的参数&#xff0c…

大语言模型推理系统综述

摘要 近年来&#xff0c;随着 ChatGPT 等服务推动大语言模型&#xff08;LLM&#xff09;的快速普及&#xff0c;一批专门面向 LLM 推理的系统相继涌现&#xff0c;如 vLLM、SGLang、Mooncake 和 DeepFlow。这些系统设计工作的核心动因是 LLM 请求处理过程中所特有的自回归特性…

用Firecrawl轻松获取网站数据,提升AI应用的效率!

&#x1f525; Firecrawl&#xff1a;助力AI应用的强大工具&#xff01; 在数字化信息爆炸的时代&#xff0c;如何高效地从海量网页中提取有用数据变得尤其重要。Firecrawl的问世&#xff0c;为我们揭开了一种便捷的方法来应对这一挑战。它不仅能够将整个网站的数据转化为适用…

【王阳明代数讲义】谷歌编程智能体Gemini CLI 使用指南、架构详解与核心框架分析

Gemini CLI 使用指南、架构详解与核心框架分析 Gemini CLI 使用指南、架构详解与核心框架分析Gemini CLI 使用指南Gemini CLI 架构详解Gemini CLI 核心框架总结 Gemini CLI 使用指南、架构详解与核心框架分析 Gemini CLI 使用指南 1. 安装与配置 环境要求&#xff1a; Node.…

camera调试:安卓添加xml注册

对接安卓的平台时&#xff0c;需要注册对应的camera设备&#xff0c;供安卓标准api进行操作&#xff0c;rk的平台需要在HAL层配置camera3_profiles.xml文件&#xff0c;适配驱动的信息&#xff0c;进行注册camera设备。该xml对应的内容很多&#xff0c;很多CTS测试问题都是该文…

使用 Ansys Discovery 为初学者准备几何结构

介绍 设计几何体通常会包含一些特征&#xff0c;使其无法直接导入我们的仿真工具&#xff0c;例如 Ansys Mechanical、LS-DYNA、Fluent 等。有些干扰或错位虽然适合制造&#xff0c;但在我们的仿真工具中却会造成问题。有时&#xff0c;一些小特征&#xff08;例如孔或圆角&am…

推客系统全栈开发指南:从架构设计到商业化落地

一、推客系统概述 推客系统&#xff08;TuiKe System&#xff09;是一种结合社交网络与内容分发的创新型平台&#xff0c;旨在通过用户间的相互推荐机制实现内容的高效传播。这类系统通常包含用户关系管理、内容发布、智能推荐、数据分析等核心模块&#xff0c;广泛应用于电商…

大数据开发实战:如何做企业级的数据服务产品

1.背景 数据服务通常以解决方案的形式进行组织&#xff0c;面向一个应用场景的所有数据需求或数据内容可以通过一个解决方案进行封装&#xff0c;统一对外服务。一个数据需求或数据接口以一个数据服务实例的形式存在于解决方案之下。 下游消费方可以通过统一API进行数据消费&…

基于IndexTTS的零样本语音合成

IndexTTS 项目采用模块化设计&#xff0c;将 BPE 文本编码、GPT 单元预测、dVAE 语音特征抽取和 BigVGAN 音频生成串联为完整的语音合成流程。系统通过统一的配置文件和模型目录规范&#xff0c;实现高效的文本到语音转换&#xff0c;支持命令行与 Web 界面双模式操作&#xff…

基于go-zero的短链生成系统

go-zero框架 gozero&#xff08;又称go-zero&#xff09;是一款由知名开发者kevwan设计的Golang微服务框架&#xff0c;专注于高性能、低延迟和易用性。其核心目标是简化分布式系统的开发&#xff0c;提供开箱即用的工具链&#xff0c;涵盖API网关、RPC服务、缓存管理、数据库…

Linux-修改线上MariaDB服务端口号

准备工作&#xff08;很重要&#xff01;&#xff01;&#xff01;&#xff09;&#xff1a; 提前做好Linux服务器快照 提前做好数据库数据备份 1. 修改配置文件 首先&#xff0c;我们需要找到MariaDB的配置文件。通常情况下&#xff0c;这个文件位于以下位置&#xff1a;…

Spring Cloud 微服务(负载均衡策略深度解析)

&#x1f4cc; 摘要 在微服务架构中&#xff0c;负载均衡是实现高可用、高性能服务调用的关键机制之一。Spring Cloud 提供了基于客户端的负载均衡组件 Ribbon&#xff0c;结合 Feign 和 OpenFeign&#xff0c;实现了服务间的智能路由与流量分配。 本文将深入讲解 Spring Clo…

HTML/CSS基础

1.html:超文本标记语言。它是一种标识性的语言&#xff0c;非编程语言&#xff0c;不能使用逻辑运算。通过标签将网络上的文本格式进行统一&#xff0c;使用分散网络资源链接为一个逻辑整体&#xff0c;属于标记语言。 超文本&#xff1a;就是指页面内可以包含图片&#xff0…

C# 事件驱动编程的核心:深度解析发布者_订阅者模式

适用场景&#xff1a;GUI交互、消息队列、微服务通信等需要解耦事件生产与消费的系统 &#x1f9e9; 模式核心组件解析 发布者&#xff08;Publisher&#xff09; 作用&#xff1a;定义事件并管理订阅者列表关键行为&#xff1a; 提供和-运算符注册/注销订阅者通过Invoke()方…