问题
数据库读写分离,如何改代码?
答案
核心概念
读写分离是通过主库处理写操作,从库处理读操作,实现数据库负载分散和性能提升。代码层面需要实现动态数据源路由。
实现方案
方案1:AbstractRoutingDataSource + AOP
核心组件:
- 数据源上下文 - 使用ThreadLocal保存当前数据源类型
- 动态数据源 - 继承AbstractRoutingDataSource实现路由
- 自定义注解 - @Master和@Slave标记方法
- AOP切面 - 拦截注解并设置数据源
关键代码结构:
DataSourceContextHolder → 存储数据源类型
DynamicDataSource → 动态选择数据源
@Master/@Slave → 业务方法注解
DataSourceAspect → AOP切面路由
优点: 代码侵入性低,灵活控制
方案2:ShardingSphere(企业级推荐)
特点:
- 零代码侵入,配置驱动
- 自动识别SQL类型并路由
- 支持多从库负载均衡
- 支持从库高可用
配置示例(application.yml):
spring:
shardingsphere:
datasource:
names: master,slave
master:
jdbc-url: jdbc:mysql://master:3306/db
username: root
password: password
slave:
jdbc-url: jdbc:mysql://slave:3306/db
username: root
password: password
rules:
readwrite-splitting:
data-sources:
readwrite_ds:
write-data-source-name: master
read-data-source-names: slave
load-balancer-name: round_robin
优点: 零侵入,自动路由,功能强大
关键场景处理
1. 强制读主库
刚写入的数据立即查询时,需强制读主库避免主从延迟影响
2. 事务内操作
同一事务内的所有操作必须使用同一数据源(主库)
3. 缓存结合
写操作更新缓存,读操作先查缓存再查从库,减少主从延迟影响
注意事项
- 主从延迟 - 关键数据强制读主库或使用缓存
- 事务一致性 - 事务内所有操作走主库
- 连接池配置 - 主库池小,从库池大
- 监控告警 - 监控延迟和连接池状态
面试答题总结
读写分离代码实现主要有两种方案:
-
AbstractRoutingDataSource + AOP:通过自定义注解+AOP切面+ThreadLocal实现动态数据源切换,适合中型项目
-
ShardingSphere:零代码侵入,配置驱动,自动SQL路由和负载均衡,企业级推荐
核心技术是AbstractRoutingDataSource + ThreadLocal。需要注意主从延迟、事务一致性、强制读主库等场景。生产环境推荐ShardingSphere,配合缓存和监控保证系统高可用。