实现数据库故障自动切换的方案可以借助数据库连接池和心跳检测机制。下面是一种常见的实现方式:
配置文件准备:
在 application.properties 或 application.yml 文件中设置主备数据库的配置,包括连接信息和其他相关配置。
连接池配置:
配置两个数据源并分别创建对应的数据库连接池对象,例如使用 HikariCP 连接池。
@Configuration
public class DataSourceConfig {
@Value("${spring.datasource.master.url}")
private String masterUrl;
@Value("${spring.datasource.master.username}")
private String masterUsername;
@Value("${spring.datasource.master.password}")
private String masterPassword;
@Value("${spring.datasource.slave.url}")
private String slaveUrl;
@Value("${spring.datasource.slave.username}")
private String slaveUsername;
@Value("${spring.datasource.slave.password}")
private String slavePassword;
@Bean("masterDataSource")
public DataSource masterDataSource() {
HikariDataSource dataSource = new HikariDataSource();
// 设置主数据库连接参数
dataSource.setJdbcUrl(masterUrl);
dataSource.setUsername(masterUsername);
dataSource.setPassword(masterPassword);
return dataSource;
}
@Bean("slaveDataSource")
public DataSource slaveDataSource() {
HikariDataSource dataSource = new HikariDataSource();
// 设置备用数据库连接参数
dataSource.setJdbcUrl(slaveUrl);
dataSource.setUsername(slaveUsername);
dataSource.setPassword(slavePassword);
return dataSource;
}
}
数据库心跳检测:
创建一个定时任务或监听器,在应用启动后定期检测主数据库的可用性。可以通过执行简单的 SQL 查询或者发送网络请求来判断数据库是否正常工作。
@Component
public class DatabaseHeartbeat {
@Autowired
private DataSource masterDataSource;
@Autowired
private DataSource slaveDataSource;
@Scheduled(fixedDelay = 5000) // 每隔5秒执行一次
public void checkDatabaseStatus() {
if (!isDatabaseAvailable(masterDataSource)) {
switchToSlaveDataSource();
}
}
private boolean isDatabaseAvailable(DataSource dataSource) {
try (Connection connection = dataSource.getConnection()) {
// 执行测试查询,例如 SELECT 1
// 如果查询成功,则返回 true,说明数据库可用
return true;
} catch (SQLException e) {
// 发生异常,则返回 false,说明数据库不可用
return false;
}
}
private void switchToSlaveDataSource() {
// 切换为备用数据源
DynamicDataSourceContextHolder.setDataSourceKey("slave");
}
}
动态数据源配置:
创建一个动态数据源,根据具体情况选择使用主数据库或备用数据库。可以使用 Spring Boot 提供的 AbstractRoutingDataSource
类实现动态数据源。
@Configuration
public class DynamicDataSourceConfig {
@Autowired
@Qualifier("masterDataSource")
private DataSource masterDataSource;
@Autowired
@Qualifier("slaveDataSource")
private DataSource slaveDataSource;
@Bean
public DataSource dynamicDataSource() {
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("master", masterDataSource);
targetDataSources.put("slave", slaveDataSource);
dataSource.setTargetDataSources(targetDataSources);
dataSource.setDefaultTargetDataSource(masterDataSource);
return dataSource;
}
}
使用注解标记数据源:
在需要切换数据源的方法上使用自定义注解,例如 @UseMasterDataSource 和 @UseSlaveDataSource 注解。
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@UseMasterDataSource
public User getUserById(Long id) {
return userRepository.findById(id);
}
@UseSlaveDataSource
public List<User> getAllUsers() {
return userRepository.findAll();
}
}
通过以上配置和代码,系统会定期检测主数据库的可用性,如果主数据库不可用,则自动切换到备用数据库,保证系统的可用性。请根据实际情况进行适当调整和优化。