Files
dsProject/Doc/13、读写分离.md
2025-08-14 15:45:08 +08:00

5.1 KiB
Raw Blame History

数据库读写分离功能说明

概述

本项目已集成数据库读写分离功能,通过修改 Db.java 类实现了自动的读写分离路由。该功能具有以下特点:

  • 自动检测:根据 application.yaml 配置自动检测是否存在从库配置
  • 智能路由:读操作自动路由到从库,写操作强制使用主库
  • 负载均衡:多个从库时随机选择一个进行读取
  • 故障转移:从库连接失败时自动回退到主库
  • 零侵入:现有代码无需修改,透明支持读写分离

配置方式

1. 主库配置(必须)

application_dev.yamlapplication_pro.yaml 中配置主库:

mysql:
  driverClassName: com.mysql.cj.jdbc.Driver
  user: root
  password: 123456
  jdbcUrl: jdbc:mysql://localhost:3306/dswork?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowMultiQueries=true

2. 从库配置(可选)

如果需要启用读写分离,添加从库配置:

mysql:
  driverClassName: com.mysql.cj.jdbc.Driver
  user: root
  password: 123456
  jdbcUrl: jdbc:mysql://localhost:3306/dswork?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowMultiQueries=true
  
  # 从库1
  slave1:
    driverClassName: com.mysql.cj.jdbc.Driver
    user: root
    password: 123456
    jdbcUrl: jdbc:mysql://slave1:3306/dswork?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowMultiQueries=true
  
  # 从库2
  slave2:
    driverClassName: com.mysql.cj.jdbc.Driver
    user: root
    password: 123456
    jdbcUrl: jdbc:mysql://slave2:3306/dswork?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowMultiQueries=true

使用方式

1. 自动读写分离(推荐)

现有代码无需修改,系统会自动根据 SQL 类型进行路由:

// 读操作 - 自动路由到从库
List<Record> users = Db.find("select * from user where status = ?", 1);
Record user = Db.findFirst("select * from user where id = ?", 123);
List<Record> result = Db.query("select count(*) from user");

// 写操作 - 强制使用主库
Db.update("insert into user(name, email) values(?, ?)", "张三", "zhangsan@example.com");
Db.update("update user set status = ? where id = ?", 1, 123);
Db.delete("delete from user where id = ?", 123);

// 事务操作 - 强制使用主库
Db.tx(() -> {
    Db.update("insert into user(name) values(?)", "李四");
    Db.update("update user set status = 1 where name = ?", "李四");
    return true;
});

2. 强制指定数据库

如果需要强制使用特定数据库,可以使用以下方法:

// 强制使用主库查询(用于需要强一致性的场景)
List<Record> users = Db.queryFromMaster("select * from user where id = ?", 123);
Record user = Db.findFirstFromMaster("select * from user where id = ?", 123);

// 强制使用指定从库查询
List<Record> users = Db.queryFromSlave(0, "select * from user"); // 使用第1个从库

3. 查看读写分离状态

// 获取读写分离状态信息
String status = Db.getReadWriteSeparationStatus();
System.out.println(status);

自动路由规则

读操作(路由到从库)

以下 SQL 语句会自动路由到从库:

  • SELECT 查询语句
  • SHOW 语句
  • DESC / DESCRIBE 语句
  • EXPLAIN 语句

对应的方法包括:

  • Db.find()Db.findFirst()Db.findById()
  • Db.query()Db.queryFirst()Db.queryXxx()
  • Db.paginate() 分页查询
  • Db.findByCache() 缓存查询

写操作(强制使用主库)

以下操作强制使用主库:

  • INSERTUPDATEDELETE 语句
  • 所有事务操作
  • Db.save()Db.update()Db.delete()
  • Db.tx() 事务方法

性能优化建议

  1. 合理配置从库数量:根据读写比例配置适当数量的从库
  2. 使用连接池:确保主从库都配置了合适的连接池参数
  3. 监控从库延迟:定期检查主从同步延迟,避免读取到过期数据
  4. 强一致性场景:对于需要强一致性的查询,使用 queryFromMaster() 方法

注意事项

  1. 主从同步延迟:从库可能存在数据同步延迟,对于实时性要求高的查询建议使用主库
  2. 事务一致性:所有事务操作都在主库执行,确保数据一致性
  3. 配置格式:从库配置必须以 slave 开头,后跟数字(如 slave1slave2
  4. 故障处理:从库连接失败时会自动回退到主库,不会影响业务正常运行

启动日志

系统启动时会输出读写分离状态信息:

[Db] 读写分离已启用,发现 2 个从库配置

[Db] 未发现从库配置,使用单库模式

故障排查

如果读写分离功能异常,请检查:

  1. 配置文件中从库配置格式是否正确
  2. 从库连接信息是否正确
  3. 从库服务是否正常运行
  4. 网络连接是否正常

系统会在控制台输出相关错误信息,便于排查问题。