业务无感知**更新数据库密码

二、数据库层:双密码(最关键,零侵入)

1)MySQL 8.0.14+(推荐,原生支持)

修改密码时保留旧密码,新旧同时可用:

-- 设置新密码,旧密码继续有效
ALTER USER 'app_user'@'%' IDENTIFIED BY '新密码' RETAIN CURRENT PASSWORD;
  • 此时旧密码、新密码都能登录
  • 过渡期(通常 5–30 分钟)让应用分批切新密码
  • 全量切完后,删除旧密码:
ALTER USER 'app_user'@'%' DISCARD OLD PASSWORD;

2)Oracle 19.12+/21c

设置密码过渡时间(例如 1 天),期间双密码有效:

-- 配置过渡时间(单位天)
ALTER PROFILE app_profile PASSWORD_ROLLOVER_TIME 1;
-- 修改密码,旧密码 1 天内仍可用
ALTER USER app_user IDENTIFIED BY 新密码;

3)低版本MySQL(无双密码)

用影子账号(同权限、同密码):

  • 主账号:app_user(当前密码)
  • 影子账号:app_user_shadow(同密码)
  • 改密时:先改主账号 → 应用切影子 → 再改影子 → 最后统一切回主账号

三、应用层:Java + 连接池热更新(不重启)

1)连接池必须支持“软驱逐”(HikariCP / Druid)

HikariCP(Spring Boot 默认)

@Configuration
public class DataSourceConfig {
    @Bean
    @RefreshScope // 配置变更自动刷新
    public HikariDataSource dataSource(
            @Value("${spring.datasource.url}") String url,
            @Value("${spring.datasource.username}") String username,
            @Value("${spring.datasource.password}") String password) {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        ds.setMaximumPoolSize(20);
        ds.setIdleTimeout(600000);
        return ds;
    }

    // 密码更新时:优雅驱逐旧连接(等当前SQL跑完)
    public void refreshPassword(String newPwd) {
        HikariDataSource ds = dataSource;
        ds.setPassword(newPwd);
        // 软驱逐:不强制断开,空闲时才关旧连接
        ds.getHikariPoolMXBean().softEvictConnections();
    }
}

Druid

// 配置监听,密码变更时:
druidDataSource.setPassword(newPwd);
druidDataSource.restart(); // 平滑重启连接池,不丢请求

2)配置中心:Nacos/Apollo 动态下发密码(核心)

  • 密码不写死在代码/本地配置,统一存在配置中心(加密存储)
  • 配置中心开启自动刷新(Nacos:refreshEnabled=true;Apollo 默认)
  • Spring 用 @RefreshScope 让数据源 Bean 动态更新
# application.yml
spring:
  datasource:
    url: jdbc:mysql://db:3306/xxx
    username: app_user
    password: ${nacos.db.password} # 从Nacos拉取,自动刷新
  cloud:
    nacos:
      config:
        server-addr: nacos:8848
        refresh-enabled: true

四、完整操作步骤(生产可直接照做)

阶段1:数据库开双密码(DBA)

ALTER USER 'app_user'@'%' IDENTIFIED BY '新密码' RETAIN CURRENT PASSWORD;

✅ 旧密码、新密码同时有效。

阶段2:配置中心更新密码(运维)

  • Nacos/Apollo 把 db.password 从旧密码改成新密码
  • 配置中心自动推送给所有实例(秒级)

阶段3:应用自动热更新(无需重启)

  • @RefreshScope 触发数据源刷新
  • 连接池软驱逐旧连接:
    • 正在执行的 SQL 正常跑完
    • 空闲连接逐步关闭
    • 新请求用新密码建连接
  • 全程无拒绝、无中断、无报错

阶段4:观察 & 收尾(5–30分钟后)

  • 监控:连接数、错误率、响应时间(无异常)
  • 全实例已切新密码后:
ALTER USER 'app_user'@'%' DISCARD OLD PASSWORD;

✅ 密码更新完成,全程零停机、零影响。


五、高并发避坑要点(必看)

  1. 不要直接改密不保留旧密码 → 瞬间断连、大量报错
  2. 连接池必须软驱逐(softEvict) → 避免强杀正在执行的SQL
  3. 分批更新配置(多实例) → 不要一次性全量推,防止瞬时抖动
  4. 密码加密存储(配置中心) → 不要明文,用AES/国密加密
  5. 监控告警 → 密码变更期间监控 SQLException、连接池队列、CPU

六、回滚方案(万一出问题)

  • 数据库:旧密码仍有效(双密码期内)
  • 配置中心:改回旧密码 → 应用自动切回
  • 全程可逆、无风险

七、简历/面试话术(直接背)

高并发项目采用数据库双密码(MySQL 8.0 RETAIN CURRENT PASSWORD)+ 配置中心(Nacos)动态刷新 + HikariCP 软驱逐方案,实现零停机、业务无感知更新数据库密码;全程新旧密码并行有效,连接平滑迁移,无报错、无中断,保障高可用。


posted @ 2026-06-08 14:45  堭鍙銤  阅读(92)  评论(0)    收藏  举报