MySQL(112)如何选择读写分离策略?

选择读写分离策略是实施读写分离的关键一步。常见的读写分离策略包括简单的读写分离和基于负载均衡的读写分离。为了实现这些策略,我们需要动态地选择数据源。下面详细介绍如何实现基于Spring Boot的读写分离,并结合代码示例展示不同策略的实现。

读写分离策略

  1. 简单读写分离:在读操作中选择从库,在写操作中选择主库。
  2. 基于负载均衡的读写分离:在读操作中,从多个从库中选择一个来分担读负载。

环境准备

假设我们使用Spring Boot和MySQL,包含一个主库和两个从库。我们将通过Spring的AbstractRoutingDataSource来实现数据源的动态切换,并使用AOP切面来区分读操作和写操作。

项目依赖

pom.xml中添加必要的依赖:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
</dependencies>

数据源配置

在数据源配置类中配置主库和从库的数据源,并设置一个路由数据源来进行读写分离。

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;@Configuration
@EnableTransactionManagement
public class DataSourceConfig {@Bean(name = "masterDataSource")public DataSource masterDataSource() {return DataSourceBuilder.create().url("jdbc:mysql://localhost:3306/db_master").username("root").password("password").driverClassName("com.mysql.cj.jdbc.Driver").build();}@Bean(name = "slaveDataSource1")public DataSource slaveDataSource1() {return DataSourceBuilder.create().url("jdbc:mysql://localhost:3306/db_slave1").username("root").password("password").driverClassName("com.mysql.cj.jdbc.Driver").build();}@Bean(name = "slaveDataSource2")public DataSource slaveDataSource2() {return DataSourceBuilder.create().url("jdbc:mysql://localhost:3306/db_slave2").username("root").password("password").driverClassName("com.mysql.cj.jdbc.Driver").build();}@Beanpublic DataSource routingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,@Qualifier("slaveDataSource1") DataSource slaveDataSource1,@Qualifier("slaveDataSource2") DataSource slaveDataSource2) {AbstractRoutingDataSource routingDataSource = new AbstractRoutingDataSource() {@Overrideprotected Object determineCurrentLookupKey() {return DbContextHolder.getDbType();}};Map<Object, Object> dataSourceMap = new HashMap<>();dataSourceMap.put(DbType.MASTER, masterDataSource);dataSourceMap.put(DbType.SLAVE1, slaveDataSource1);dataSourceMap.put(DbType.SLAVE2, slaveDataSource2);routingDataSource.setDefaultTargetDataSource(masterDataSource);routingDataSource.setTargetDataSources(dataSourceMap);return routingDataSource;}@Beanpublic JdbcTemplate jdbcTemplate(DataSource dataSource) {return new JdbcTemplate(dataSource);}
}

数据源上下文

定义一个上下文类来存储当前的数据库类型(主库或从库):

public class DbContextHolder {private static final ThreadLocal<DbType> contextHolder = new ThreadLocal<>();public static void setDbType(DbType dbType) {contextHolder.set(dbType);}public static DbType getDbType() {return contextHolder.get();}public static void clearDbType() {contextHolder.remove();}
}public enum DbType {MASTER,SLAVE1,SLAVE2
}

AOP切面实现

使用AOP切面实现读写分离。在读操作前设置数据源为从库,在写操作前设置数据源为主库。

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;import java.util.concurrent.atomic.AtomicInteger;@Aspect
@Component
public class DataSourceAspect {private AtomicInteger counter = new AtomicInteger(0);@Before("execution(* com.example.service.*.find*(..)) || execution(* com.example.service.*.get*(..))")public void setReadDataSourceType() {// 简单轮询策略,负载均衡int index = counter.incrementAndGet() % 2;if (index == 0) {DbContextHolder.setDbType(DbType.SLAVE1);} else {DbContextHolder.setDbType(DbType.SLAVE2);}}@Before("execution(* com.example.service.*.insert*(..)) || execution(* com.example.service.*.update*(..)) || execution(* com.example.service.*.delete*(..))")public void setWriteDataSourceType() {DbContextHolder.setDbType(DbType.MASTER);}
}

数据库操作服务实现

实现具体的数据库操作服务类:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class OrderService {@Autowiredprivate JdbcTemplate jdbcTemplate;public void insertOrder(String orderId, String productName, double price) {String sql = "INSERT INTO orders (order_id, product_name, price) VALUES (?, ?, ?)";jdbcTemplate.update(sql, orderId, productName, price);}public List<Order> getOrdersByProductName(String productName) {String sql = "SELECT * FROM orders WHERE product_name = ?";return jdbcTemplate.query(sql, new Object[]{productName}, (rs, rowNum) ->new Order(rs.getString("order_id"), rs.getString("product_name"), rs.getDouble("price")));}
}

测试读写分离

通过调用OrderService中的方法进行测试:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;import java.util.List;@Component
public class TestRunner implements CommandLineRunner {@Autowiredprivate OrderService orderService;@Overridepublic void run(String... args) throws Exception {// 插入数据orderService.insertOrder("order1", "Product A", 100.0);// 查询数据List<Order> orders = orderService.getOrdersByProductName("Product A");orders.forEach(System.out::println);}
}

结论

通过以上步骤,我们展示了如何实现基于Spring Boot的读写分离策略。关键点如下:

  1. 数据源配置:配置主库和从库的数据源,并设置路由数据源来进行读写分离。
  2. 数据源上下文:定义一个上下文类来存储当前的数据库类型(主库或从库)。
  3. AOP切面实现:使用AOP切面在读操作和写操作前分别设置数据源为从库和主库。通过简单轮询策略实现负载均衡。
  4. 数据库操作服务实现:实现具体的数据库操作服务类,通过JdbcTemplate进行数据库操作。

这种方法可以有效地实现数据库读写分离和负载均衡,提高系统的性能和可扩展性。你可以根据实际需求选择和调整读写分离策略。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/89543.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/89543.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

日志-解决Linux因target is busy无法卸载硬盘/分区的问题 - PHP持续占用分区

效果图 写在前面 此次遇到的问题是&#xff0c;php-fpm持续占用设备/mnt/disk1&#xff0c;强制杀死php所有进程后&#xff0c;依然会自动产生新的进程再次霸占分区&#xff0c;导致设备无法卸载umount。思路是解决谁在不停的捣乱。 步骤 核心&#xff1a; 挂载文件系统到指定…

Linux系统权限维持篇

Openssh后门 重新安装自定义的openssh&#xff0c;达到记录账户密码&#xff0c;也可以采用万能密码连接的功能 1、登录方式 2、登录软件 3、登录机制 环境准备 yum -y install openssl openssl-devel pam-devel zlib zlib-devel yum -y install gcc gcc-c makewget http://c…

spring中maven缺少包如何重新加载,报错java: 程序包org.springframework.web.reactive.function不存在

错误原因分析 java: 程序包org.springframework.web.reactive.function不存在 这个错误是由于 项目中缺少 Spring WebFlux 相关依赖 导致的。org.springframework.web.reactive.function 包属于 Spring WebFlux 模块&#xff08;用于响应式 Web 开发&#xff09;&#xff0c;如…

Linux--线程池

目录 Linux线程池 线程池的概念 线程池的优点 线程池的应用场景 线程池的实现 Linux线程池 线程池的概念 线程池是一种线程的使用模式。 其存在的主要原因就为&#xff1a;线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能。而线程池维护着多个线程&#…

mars3d (基于 Cesium 的轻量化三维地图库)

mars3d 是什么? Mars3D 作为基于 Cesium 的轻量化框架,正以其简洁的 API 和强大的功能重新定义开发体验。它不仅解决了原生 Cesium 学习曲线陡峭的问题,还通过封装和优化实现了性能与易用性的双重突破。无论是智慧城市、低空经济还是军事仿真,Mars3D 都能提供高效的三维可视…

uniapp 中使用路由导航守卫,进行登录鉴权

前言: 在uniapp 使用中,对于登录界面可能需要路由守卫进行方便判断跳转,以下有两种方案,可以判断用户跳转的时候是否是登录状态 方案一: 1. 可以使用插件 hh-router-guard 2. 使用 uni-simpe-route 方案二: 使用通过uni提供的拦截器实现, uni.addInterceptor 1.新建in…

Leetcode 262. 行程和用户

1.题目基本信息 1.1.题目描述 表&#xff1a;Trips ----------------------- | Column Name | Type | ----------------------- | id | int | | client_id | int | | driver_id | int | | city_id | int | | status | enum | | request_at | varchar | -----------…

P1102 A-B 数对

P1102 A-B 数对 题目背景 出题是一件痛苦的事情! 相同的题目看多了也会有审美疲劳,于是我舍弃了大家所熟悉的 A+B Problem,改用 A-B 了哈哈! 题目描述 给出一串正整数数列以及一个正整数 C C C,要求计算出所有满足 A − B = C A - B = C A−B=C 的数对的个数(不同…

devextreme-vue的DxDataGrid如何显示行号列

devextreme-vue我使用的是23.2版本&#xff0c;其DxDataGrid如何显示行号列&#xff0c;官方一直没有方案。 DataGrid - How to display a row number in data rows in Angular | DevExpress Support dxDataGrid - provide capability to display a column with row numbers …

【设计模式06】建造者模式

前言 没什么用&#xff0c;类似于builder.build UML类图 代码示例 package com.sw.learn.pattern.B_create.e_builder;import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt();for …

datax-web报错:连接数据库失败. 请检查您的 账号、密码、数据库名称、IP、Port或者向 DBA 寻求帮助(注意网络环境)

文章目录 一、报错内容二、解决方法 一、报错内容 背景描述&#xff1a; 在linux安装了datax202309版本及datax-web2.1.2版本&#xff0c;datax与datax-web默认都是mysql5.x版本的。我的数据库是mysql8.x版本的。 在datax中执行json脚本从一个mysql导入mysql没问题&#xff0…

C#调用C++导出的dll怎么调试进入C++ DLL源码

第一步&#xff1a;首先需要打开C源码&#xff0c;不需要任何设置&#xff0c;直接下断点&#xff0c;然后将生成DLL目录改成到C# exe生成目录里面 第二步&#xff1a;打开winform项目&#xff0c;然后在C#项目属性->启用本地代码调试勾选后即可 最后在C#下断点F10或者F11…

Skyeye 云智能制造办公系统 - Saas v3.16.10 发布

Skyeye 云智能制造&#xff0c;采用 Springboot (微服务) Layui UNI-APP Ant Design Vue 的低代码平台。包含 30 多个应用模块、50 多种电子流程&#xff0c;CRM、PM、ERP、MES、ADM、EHR、笔记、知识库、项目、门店、商城、财务、多班次考勤、薪资、招聘、云售后、论坛、公…

pdf 合并 python实现(已解决)

在Python中&#xff0c;可以使用多种库来合并PDF文件&#xff0c;其中最常用的是PyPDF2和PyMuPDF&#xff08;又名fitz&#xff09;。下面我将分别介绍如何使用这两个库来合并PDF文件。 使用PyPDF2 首先&#xff0c;你需要安装PyPDF2。可以使用pip来安装&#xff1a; 先按照库…

VCenter SSL过期,登录提示HTTP 500错误解决办法

报错图&#xff1a; 1. 开启 VCenter ssh远程连接 登录vmware esxi&#xff0c;双击打开VCenter 控制台黑窗口&#xff0c;根据提示按F2键 两次&#xff0c;打开系统设置&#xff08;有fn键使用fnF2键&#xff09; 输入root密码&#xff0c;按回车登录 选择“Troubleshooting …

Linux 下安装Oracle 11gR2 x64 netca启动不了

前言 Oracle Network Configuration Assistant (netca) 是 Oracle 提供的图形化网络配置工具&#xff0c;用于简化 Oracle 数据库网络组件的配置和管理。 核心功能 1、配置监听器 (LISTENER)创建、修改或删除数据库监听器&#xff08;默认端口 1521&#xff09;定义监听协议…

Pytorch1线性代数实现

Pytorch --线性代数实现 矩阵 正如向量将标量从零阶推广到一阶&#xff0c;矩阵将向量从一阶推广到二阶。 矩阵&#xff0c;我们通常用粗体、大写字母来表示 &#xff08;例如&#xff0c;&#x1d44b;、&#x1d44c;和&#x1d44d;&#xff09;&#xff0c; 在代码中表示…

行业分享丨泛亚汽车数字化转型实践:虚拟仿真技术如何赋能汽车研发的创新实践?

随着汽车行业向智能化、电动化快速转型&#xff0c;虚拟仿真技术正成为推动产品研发变革的核心驱动力。作为行业技术先锋&#xff0c;泛亚汽车通过系统性布局&#xff0c;构建了完整的虚拟仿真技术体系&#xff0c;并总结出三个关键方向&#xff1a;打造数字化研发体系、探索精…

【硬核数学】4. AI的“寻路”艺术:优化理论如何找到模型的最优解《从零构建机器学习、深度学习到LLM的数学认知》

欢迎来到本系列的第四篇文章。我们已经知道&#xff0c;训练一个AI模型&#xff0c;本质上是在寻找一组参数&#xff0c;使得描述模型“有多差”的损失函数 L ( θ ) L(\theta) L(θ) 达到最小值。微积分给了我们强大的工具——梯度下降&#xff0c;告诉我们如何一步步地向着最…

springboot切面编程

SpringBoot切面编程 众所周知&#xff0c;spring最核心的两个功能是aop和ioc&#xff0c;即面向切面和控制反转。本文会讲一讲SpringBoot如何使用AOP实现面向切面的过程原理。 何为AOP AOP&#xff08;Aspect OrientedProgramming&#xff09;&#xff1a;面向切面编程&…