Spring Boot+MyBatis+MySQL如何实现读写分离

 ​

博客主页:     南来_北往

系列专栏:Spring Boot实战


背景

读写分离是数据库架构中的一种优化策略,它将读操作(查询)和写操作(更新、插入、删除)分开处理,通常通过将读请求和写请求分别发送到不同的数据库服务器来实现。下面介绍实现读写分离的原因:

  1. 提高并发能力:在高并发访问场景下,读写分离可以有效地分散请求,提高系统的整体性能。例如,在电商平台中,用户浏览商品的次数远超实际购买的次数,因此将读取操作分配给专门的读库,可以显著降低对主数据库的压力。
  2. 优化资源利用:对于数据分析和报告生成任务,需要大量数据读取,而通过读写分离,这些操作不会影响在线事务处理的性能。这样,企业可以进行高效的数据分析,同时确保日常业务的稳定运行。
  3. 提升读取性能:读写分离通过多台读库分摊读取压力,从而大幅提升读性能。这对于需要快速响应的数据检索需求尤为关键。
  4. 减轻写入负担:在互联网应用中,写操作通常比读操作耗时得多。通过将写操作集中在一个数据库上,并同步到多个读库,可以保证写操作的效率和一致性。
  5. 应对不同场景:读写分离适用于多种业务场景,包括高并发访问、数据分析和报告、以及数据仓库等。在这些场景中,读写分离能够优化资源分配,满足不同的业务需求。
  6. 支持决策分析:通过读写分离,可以前置处理大量的汇总数据,使得企业的决策分析更加迅速和准确。例如,某公司采用基于FDL的离线数仓方案进行读写分离后,大幅提高了BI报表的稳定性和数据的决策分析能力。

总之,读写分离不仅能有效提升数据库性能,还能根据不同的业务需求,提供灵活的数据处理能力。然而,在实施时也需考虑数据同步延迟、一致性等问题,以确保系统整体的稳定性和可靠性。

实践

1、配置数据源:在application.properties或application.yml文件中配置两个数据源,一个用于读操作(slave),另一个用于写操作(master)。

# application.yml
spring:datasource:master:url: jdbc:mysql://localhost:3306/master_db?useSSL=false&serverTimezone=UTCusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driverslave:url: jdbc:mysql://localhost:3306/slave_db?useSSL=false&serverTimezone=UTCusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver

 2、创建数据源配置类:创建一个配置类,用于创建和配置两个数据源。

@Configuration
public class DataSourceConfig {@Bean(name = "masterDataSource")@ConfigurationProperties(prefix = "spring.datasource.master")public DataSource masterDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "slaveDataSource")@ConfigurationProperties(prefix = "spring.datasource.slave")public DataSource slaveDataSource() {return DataSourceBuilder.create().build();}
}

 3、建SqlSessionFactory:为每个数据源创建一个SqlSessionFactory。

@Configuration
public class MyBatisConfig {@Autowired@Qualifier("masterDataSource")private DataSource masterDataSource;@Autowired@Qualifier("slaveDataSource")private DataSource slaveDataSource;@Bean(name = "masterSqlSessionFactory")public SqlSessionFactory masterSqlSessionFactory() throws Exception {SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(masterDataSource);return factoryBean.getObject();}@Bean(name = "slaveSqlSessionFactory")public SqlSessionFactory slaveSqlSessionFactory() throws Exception {SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(slaveDataSource);return factoryBean.getObject();}
}

4、建事务管理器:为每个数据源创建一个事务管理器。

@Configuration
public class TransactionManagerConfig {@Autowired@Qualifier("masterDataSource")private DataSource masterDataSource;@Autowired@Qualifier("slaveDataSource")private DataSource slaveDataSource;@Bean(name = "masterTransactionManager")public DataSourceTransactionManager masterTransactionManager() {return new DataSourceTransactionManager(masterDataSource);}@Bean(name = "slaveTransactionManager")public DataSourceTransactionManager slaveTransactionManager() {return new DataSourceTransactionManager(slaveDataSource);}
}

5、建动态数据源:根据需要切换不同的数据源。

public class DynamicDataSource extends AbstractRoutingDataSource {private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();public static void setDataSource(String dataSource) {contextHolder.set(dataSource);}public static String getDataSource() {return contextHolder.get();}public static void clearDataSource() {contextHolder.remove();}@Overrideprotected Object determineCurrentLookupKey() {return getDataSource();}
}

 6、配置动态数据源:将动态数据源与SqlSessionFactory和事务管理器关联。

@Configuration
public class DataSourceConfig {@Autowired@Qualifier("masterSqlSessionFactory")private SqlSessionFactory masterSqlSessionFactory;@Autowired@Qualifier("slaveSqlSessionFactory")private SqlSessionFactory slaveSqlSessionFactory;@Autowired@Qualifier("masterTransactionManager")private DataSourceTransactionManager masterTransactionManager;@Autowired@Qualifier("slaveTransactionManager")private DataSourceTransactionManager slaveTransactionManager;@Bean(name = "dynamicDataSource")public DataSource dynamicDataSource() {DynamicDataSource dynamicDataSource = new DynamicDataSource();Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put("master", masterSqlSessionFactory);targetDataSources.put("slave", slaveSqlSessionFactory);dynamicDataSource.setTargetDataSources(targetDataSources);dynamicDataSource.setDefaultTargetDataSource(masterSqlSessionFactory);return dynamicDataSource;}@Bean(name = "transactionManager")public PlatformTransactionManager transactionManager() {DynamicDataSourceTransactionManager transactionManager = new DynamicDataSourceTransactionManager();transactionManager.setTransactionManagers(Arrays.asList(masterTransactionManager, slaveTransactionManager));return transactionManager;}
}

 7、用注解切换数据源:在Service层的方法上使用@DS注解来切换数据源。例如,读取操作使用从库,写入操作使用主库。

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;@DS("master")public void addUser(User user) {userMapper.insert(user);}@DS("slave")public List<User> findAllUsers() {return userMapper.selectAll();}
}

8、最后,需要在启动类上添加@EnableTransactionManagement注解以启用事务管理。

@SpringBootApplication
@EnableTransactionManagement
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

 

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

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

相关文章

正点原子imx6ull-mini-Linux驱动之异步通知实验(13)

在前面使用阻塞或者非阻塞的方式来读取驱动中按键值都是应用程序主动读取的&#xff0c;对于非 阻塞方式来说还需要应用程序通过 poll 函数不断的轮询。最好的方式就是驱动程序能主动向应 用程序发出通知&#xff0c;报告自己可以访问&#xff0c;然后应用程序在从驱动程序中读…

传统CS网络的新生——基于2G网络的远程灌溉实现

概述&#xff1a;iphone 实现远程电话触发&#xff0c;实现灌溉绿植的一般方法 方法一&#xff1a; 远程电话触发&#xff0c;音频线左右声道会产生一个信号&#xff0c;可以在后端利用SR锁存器暂存信号&#xff0c;后级可以接相应的控制电路实现灌溉。 方法二&#xff1a; 同…

【JavaScript】详解默认导出和命名导出的区别

文章目录 一、默认导出二、命名导出三、默认导出和命名导出的区别四、实际应用案例五、总结 在JavaScript模块化开发中&#xff0c;导入和导出模块是核心操作。ES6引入的模块化语法提供了两种主要的导出方式&#xff1a;默认导出&#xff08;default export&#xff09;和命名导…

【数学建模】——【A题 信用风险识别问题】全面解析

目录 1.题目 2.解答分析 问题1&#xff1a;指标筛选 1.1 问题背景 1.2 数据预处理 1.3 特征选择方法 1.4 多重共线性检测 1.5 实现步骤 问题2&#xff1a;信用评分模型 2.1 问题背景 2.2 数据分割 2.3 处理不平衡数据 2.4 模型选择与理由 问题3&#xff1a;模型对…

notes for datawhale summer camp chemistry task3

Transformer transformer的诞生 循环神经网络&#xff1a;由于所有的前文信息都蕴含在一个隐向量里面&#xff0c;这会导致随着序列长度的增加&#xff0c;编码在隐藏状态中的序列早期的上下文信息被逐渐遗忘。 卷积神经网络&#xff1a;受限的上下文窗口在建模长文本方面天…

Taming Lookup Tables for Efficient Image Retouching

Abstract 高清屏幕在终端用户相机、智能手机和电视等边缘设备中的广泛使用&#xff0c;刺激了对图像增强的巨大需求。现有的增强模型通常针对高性能进行优化&#xff0c;但不能减少硬件推断时间和功耗&#xff0c;尤其是在计算和存储资源受限的边缘设备上。为此&#xff0c;我…

信息学奥赛初赛天天练-53-CSP-J2019阅读程序2-模拟算法在数组中典型应用

PDF文档公众号回复关键字:20240802 2019 CSP-J 阅读程序2 1阅读程序(程序输入不超过数组或字符串定义的范围&#xff1b;判断题正确填 √&#xff0c;错误填 。除特殊说明外&#xff0c;判断题 1.5 分&#xff0c;选择题 3 分&#xff0c;共计 40 分) 假设输入的n和m都是正整…

前端Web-JavaScript(上)

要想让网页具备一定的交互效果&#xff0c;具有一定的动作行为&#xff0c;还得通过JavaScript来实现, 这门语言会让我们的页面能够和用户进行交互。 什么是JavaScript JavaScript&#xff08;简称&#xff1a;JS&#xff09; 是一门跨平台、面向对象的脚本语言&#xff0c;是…

【C++11】:右值引用移动语义完美转发

目录 前言一&#xff0c;左值引用和右值引用二&#xff0c;左值引用与右值引用比较三&#xff0c;探索引用的底层四&#xff0c;右值引用使用场景和意义4.1 解决返回值问题4.2 STL容器插入接口的改变 五&#xff0c;移动语义六&#xff0c;完美转发6.1 模板中的&& 万能…

产品经理如何快速掌握大模型技术,享受AI红利?

前言 随着人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;AI产品经理的角色变得越来越重要。尽管AI产品经理并不是一个新鲜的概念&#xff0c;但随着AI技术的迭代升级&#xff0c;这一角色的重要性得到了显著提升。 AI产品经理的演变 早期的AI产品可能并不会…

网络原理的TCP/IP

TCP/IP协议 1)应用层 应用层和应用程序直接相关,与程序员息息相关的一层协议,应用层协议,里面描述的内容,就是写的程序,通过网络具体按照啥样的方式来进行传输,不同的应用程序,就可以用不同的应用层协议,在实际开发的过程中,需要程序员自制应用层协议 应用层协议本质上就是对…

python: 多进程实例

1. 实例一 主进程跟子进程的通过两个队列实现全双工通信&#xff1b;如有需要主进程会提示窗口输入信息传输给子进程&#xff1b;如果子进程收到主进程的消息&#xff0c;会弹窗提示收到的消息&#xff1b;子进程弹窗提示进程即将结束&#xff1b; 详细代码如下 # -*- coding…

独立站+TikTok达人:自主营销与创意内容的完美结合

在全球电商市场迅猛发展的今天&#xff0c;独立站和TikTok达人的结合正在创造一种全新的电商营销模式。独立站作为电商平台&#xff0c;其自主性和灵活性为商家提供了广阔的发展空间&#xff1b;而TikTok达人凭借其独特的内容创作能力和庞大的粉丝基础&#xff0c;成为推动销售…

OpenStack;异构算力网络架构;算力服务与交易技术;服务编排与调度技术

目录 OpenStack 一、OpenStack概述 二、OpenStack的主要组件及功能 三、OpenStack的架构 四、OpenStack的应用场景 异构算力网络架构 算力服务与交易技术 服务编排与调度技术 OpenStack 是一个开源的云计算管理平台项目,由NASA(美国国家航空航天局)和Rackspace合作…

「AI绘画Stable Diffusion 零基础入门 」AI 绘画SD原理与工具介绍,万字详解新手入门必看!

大家好&#xff0c;我是设计师阿威 AI 绘画原理 想要入门 AI 绘画&#xff0c;首先需要了解它的原理是什么样的。 其实很早就已经有人基于深度学习模型展开了对图像生成的研究了&#xff0c;但在那时&#xff0c;生成的图像分辨率和内容都非常抽象。 直到近两年&#xff0c…

C++必修:STL之vector的模拟实现

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C学习 贝蒂的主页&#xff1a;Betty’s blog 为了让我们更加深入理解vector&#xff0c;接下来我们将模拟实现一个简易版的vect…

二叉树链式结构的实现(递归的暴力美学!!)

前言 Hello,小伙伴们。你们的作者菌又回来了&#xff0c;前些时间我们刚学习完二叉树的顺序结构&#xff0c;今天我们就趁热打铁&#xff0c;继续我们二叉树链式结构的学习。我们上期有提到&#xff0c;二叉树的的底层结构可以选为数组和链表&#xff0c;顺序结构我们选用的数…

将YOLOv8模型从PyTorch的.pt格式转换为OpenVINO支持的IR格式

OpenVINO是Open Visual Inference & Neural Network Optimization工具包的缩写&#xff0c;是一个用于优化和部署AI推理模型的综合工具包。OpenVINO支持CPU、GPU和NPU设备。 OpenVINO的优势: (1).性能&#xff1a;OpenVINO利用英特尔CPU、集成和独立GPU以及FPGA的强大功能提…

PHP学习:PHP基础

以.php作为后缀结尾的文件&#xff0c;由服务器解析和运行的语言。 一、语法 PHP 脚本可以放在文档中的任何位置。 PHP 脚本以 <?php 开始&#xff0c;以 ?> 结束。 <!DOCTYPE html> <html> <body><h1>My first PHP page</h1><?php …