欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 建筑 > 【SQL】什么是数据库读写分离

【SQL】什么是数据库读写分离

2024/10/24 23:27:07 来源:https://blog.csdn.net/hui_zai_/article/details/140385681  浏览:    关键词:【SQL】什么是数据库读写分离

数据库读写分离是一种数据库架构设计,用于提高数据库的性能和可扩展性。其基本思想是将数据库的读操作和写操作分离开来,通过不同的数据库实例处理,从而减轻单个数据库实例的负载,提升整体系统的吞吐量和响应速度。

读写分离的基本概念

  1. 主库(Master):处理所有的写操作(插入、更新、删除)和一些关键的读操作。主库是数据的唯一写入点,确保数据的一致性。
  2. 从库(Slave):从主库复制数据,处理所有的读操作。一个主库可以有多个从库,从库之间的数据是从主库同步过来的,通常是实时或接近实时的。

读写分离的实现步骤

  1. 主从复制:配置主库和从库,实现数据同步。常见的数据库,如 MySQL,提供了内置的主从复制功能。
  2. 读写路由:在应用程序层或中间件层实现读写操作的路由。写操作路由到主库,读操作路由到从库。
  3. 数据一致性:处理主从延迟,确保在允许的范围内读到最新的数据。

Java 实现读写分离

以下是一个简单的示例,演示如何在 Java 应用程序中实现数据库的读写分离。这个示例假设使用 Spring Framework 和 HikariCP 数据源池。

数据库配置
# application.yml
spring:datasource:url: jdbc:mysql://master-db:3306/mydbusername: rootpassword: roothikari:maximum-pool-size: 10replicas:- url: jdbc:mysql://slave-db1:3306/mydbusername: rootpassword: root- url: jdbc:mysql://slave-db2:3306/mydbusername: rootpassword: root
数据源配置
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;@Configuration
public class DataSourceConfig {@Value("${spring.datasource.url}")private String masterUrl;@Value("${spring.datasource.username}")private String masterUsername;@Value("${spring.datasource.password}")private String masterPassword;@Autowiredprivate ReplicaDataSourceProperties replicaProperties;@Beanpublic DataSource dataSource() {AbstractRoutingDataSource routingDataSource = new ReplicationRoutingDataSource();HikariDataSource masterDataSource = new HikariDataSource();masterDataSource.setJdbcUrl(masterUrl);masterDataSource.setUsername(masterUsername);masterDataSource.setPassword(masterPassword);Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put("master", masterDataSource);for (int i = 0; i < replicaProperties.getReplicas().size(); i++) {ReplicaProperties replica = replicaProperties.getReplicas().get(i);HikariDataSource slaveDataSource = new HikariDataSource();slaveDataSource.setJdbcUrl(replica.getUrl());slaveDataSource.setUsername(replica.getUsername());slaveDataSource.setPassword(replica.getPassword());targetDataSources.put("slave" + i, slaveDataSource);}routingDataSource.setTargetDataSources(targetDataSources);routingDataSource.setDefaultTargetDataSource(masterDataSource);return routingDataSource;}
}
路由数据源
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;public class ReplicationRoutingDataSource extends AbstractRoutingDataSource {private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();public static void setDataSourceType(String dataSourceType) {contextHolder.set(dataSourceType);}public static void clearDataSourceType() {contextHolder.remove();}@Overrideprotected Object determineCurrentLookupKey() {return contextHolder.get();}
}
数据源选择器
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class DataSourceAspect {@Before("@annotation(com.example.annotation.Master)")public void setWriteDataSourceType() {ReplicationRoutingDataSource.setDataSourceType("master");}@Before("@annotation(com.example.annotation.Slave) || execution(* com.example.service..*.find*(..))")public void setReadDataSourceType() {ReplicationRoutingDataSource.setDataSourceType("slave0"); // 可实现负载均衡策略}
}
自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Master {
}@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Slave {
}

示例服务

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@Master@Transactionalpublic void saveUser(User user) {userRepository.save(user);}@Slavepublic User findUserById(Long id) {return userRepository.findById(id).orElse(null);}
}

总结

读写分离通过将读操作和写操作分开处理,可以大幅提高数据库系统的性能和扩展性。上面的示例展示了如何使用 Spring 和 HikariCP 实现基本的读写分离。实际应用中,可以根据业务需求进一步优化和扩展,例如添加更多的从库,优化负载均衡策略,处理数据一致性问题等。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com