Spring Boot项目优雅实现读写分离

news2024/12/24 9:13:11

文章目录

    • 1. 读写分离简介
    • 2. Spring Boot集成MyBatis
    • 3. 配置读写分离数据源
    • 4. 定义数据源上下文
    • 5. 自定义注解和切面
    • 6. 在Service层使用注解
    • 7. 拓展与分析
      • 7.1 多数据源的选择
      • 7.2 事务的处理
      • 7.3 异常处理
      • 7.4 动态数据源切换
      • 7.5 Spring Boot版本适配

在这里插入图片描述

🎉欢迎来到架构设计专栏~Spring Boot项目优雅实现读写分离


  • ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹
  • ✨博客主页:IT·陈寒的博客
  • 🎈该系列文章专栏:架构设计
  • 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习
  • 🍹文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
  • 📜 欢迎大家关注! ❤️

Spring Boot作为一种快速开发框架,广泛应用于Java项目中。在一些大型应用中,数据库的读写分离是提升性能和扩展性的一种重要手段。本文将介绍如何在Spring Boot项目中优雅地实现读写分离,并通过适当的代码插入,详细展开实现步骤,同时进行拓展和分析。
在这里插入图片描述

1. 读写分离简介

读写分离是指在数据库集群中,将数据库的读操作和写操作分别分配到不同的节点上。这样可以充分利用多台服务器的资源,提高系统的并发处理能力。一般来说,写操作相对读操作更为耗时,通过读写分离,可以有效减轻主库的负担。

2. Spring Boot集成MyBatis

首先,我们需要在Spring Boot项目中集成MyBatis,作为数据库访问的ORM框架。可以通过在pom.xml文件中添加依赖来引入MyBatis和MyBatis-Spring-Boot-Starter:

<!-- MyBatis依赖 -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.0</version>
</dependency>

<!-- 数据库连接池依赖(这里以HikariCP为例) -->
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
</dependency>

然后,配置application.properties文件,指定数据库连接信息:

# 主库
spring.datasource.master.url=jdbc:mysql://master-host:3306/master_db
spring.datasource.master.username=root
spring.datasource.master.password=root
# 从库
spring.datasource.slave.url=jdbc:mysql://slave-host:3306/slave_db
spring.datasource.slave.username=root
spring.datasource.slave.password=root

3. 配置读写分离数据源

在实现读写分离前,我们需要定义一个数据源路由器,用于根据不同的操作选择不同的数据源。在Spring Boot中,可以通过AbstractRoutingDataSource实现这一功能。以下是一个简单的数据源路由器示例:

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class RoutingDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceType();
    }
}

在上述代码中,determineCurrentLookupKey方法用于确定当前使用的数据源,DataSourceContextHolder是一个自定义的上下文持有类,用于存储当前线程使用的数据源类型。接下来,我们需要在配置类中配置这个数据源路由器:

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@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();
    }

    @Bean(name = "routingDataSource")
    public RoutingDataSource routingDataSource(
            @Qualifier("masterDataSource") DataSource masterDataSource,
            @Qualifier("slaveDataSource") DataSource slaveDataSource) {
        RoutingDataSource routingDataSource = new RoutingDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceType.MASTER, masterDataSource);
        targetDataSources.put(DataSourceType.SLAVE, slaveDataSource);
        routingDataSource.setTargetDataSources(targetDataSources);
        routingDataSource.setDefaultTargetDataSource(masterDataSource);
        return routingDataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager(DataSource routingDataSource) {
        return new DataSourceTransactionManager(routingDataSource);
    }
}

在上述代码中,我们配置了两个数据源,一个用于主库,一个用于从库。然后,通过routingDataSource方法创建了一个RoutingDataSource实例,将主库和从库加入到数据源路由器中,并设置默认数据源为主库。

4. 定义数据源上下文

接下来,我们需要定义一个数据源上下文类,用于在当前线程中保存和获取当前使用的数据源类型。这个上下文类应该是线程安全的,因为它会在多个线程中被访问。

public class DataSourceContextHolder {

    private static final ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<>();

    public static void setDataSourceType(DataSourceType dataSourceType) {
        contextHolder.set(dataSourceType);
    }

    public static DataSourceType getDataSourceType() {
        return contextHolder.get();
    }

    public static void clearDataSourceType() {
        contextHolder.remove();
    }
}

5. 自定义注解和切面

为了在Service层标注读操作和写操作,我们可以定义两个自定义注解@Master@Slave,并创建一个切面DataSourceAspect,通过AOP切入点拦截被这两个注解标记的方法,然后在方法执行前设置数据源类型。

@Aspect
@Component
public class DataSourceAspect {

    @Before("@annotation(master)")
    public void setMasterDataSource(JoinPoint joinPoint, Master master) {
        DataSource

ContextHolder.setDataSourceType(DataSourceType.MASTER);
    }

    @Before("@annotation(slave)")
    public void setSlaveDataSource(JoinPoint joinPoint, Slave slave) {
        DataSourceContextHolder.setDataSourceType(DataSourceType.SLAVE);
    }

    @After("@annotation(master) || @annotation(slave)")
    public void clearDataSourceType(JoinPoint joinPoint, Master master, Slave slave) {
        DataSourceContextHolder.clearDataSourceType();
    }
}

在上述代码中,通过@Before注解定义了两个切入点,分别拦截被@Master@Slave注解标记的方法,在方法执行前设置对应的数据源类型。在@After注解中清除当前线程的数据源类型。

6. 在Service层使用注解

最后,在Service层需要进行读写分离的方法上使用定义好的注解,标记读操作和写操作。以下是一个示例:

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Master
    public User getUserById(int userId) {
        return userMapper.selectById(userId);
    }

    @Slave
    public List<User> listAllUsers() {
        return userMapper.selectAll();
    }

    @Master
    public void saveUser(User user) {
        userMapper.insert(user);
    }
}

在上述示例中,@Master@Slave注解分别用于标记读操作和写操作的方法。在实际应用中,根据具体需求和业务场景进行灵活使用。

7. 拓展与分析

7.1 多数据源的选择

上述示例中使用了两个数据源,一个用于主库,一个用于从库。在实际应用中,如果有多个从库,可以在配置类中配置多个从库数据源,然后在数据源路由器中动态选择。

7.2 事务的处理

在涉及到事务的场景中,需要注意对事务的处理。在使用读写分离的情况下,一般将写操作放在事务中,而读操作不放在事务中。因为事务一般需要使用主库,而从库主要用于读取操作,不参与事务的提交与回滚。

7.3 异常处理

在使用读写分离的过程中,可能会遇到主从同步延迟导致的数据不一致问题。因此,在涉及到数据一致性要求较高的业务场景中,需要谨慎使用读写分离,考虑一些其他的解决方案,如数据的多版本控制等。

7.4 动态数据源切换

上述示例中使用AOP切面在方法执行前设置数据源类型。在某些场景中,可能需要在代码中动态切换数据源,这时可以通过编程式的方式设置数据源类型,而不是依赖AOP。

7.5 Spring Boot版本适配

请注意根据使用的Spring Boot版本来选择相应的依赖版本。在示例中,使用的MyBatis版本是2.2.0,如果使用的是较新的Spring Boot版本,建议查阅官方文档或相关依赖库的最新版本。

在这里插入图片描述

通过上述步骤,我们完成了Spring Boot项目中读写分离的优雅实现。通过合理的代码插入,详细展开了每个步骤的实现,并对一些拓展和分析进行了说明。希望这篇文章对正在进行数据库优化的开发者有所帮助。


🧸结尾 ❤️ 感谢您的支持和鼓励! 😊🙏
📜您可能感兴趣的内容:

  • 【Java面试技巧】Java面试八股文 - 掌握面试必备知识(目录篇)
  • 【Java学习路线】2023年完整版Java学习路线图
  • 【AIGC人工智能】Chat GPT是什么,初学者怎么使用Chat GPT,需要注意些什么
  • 【Java实战项目】SpringBoot+SSM实战:打造高效便捷的企业级Java外卖订购系统
  • 【数据结构学习】从零起步:学习数据结构的完整路径

在这里插入图片描述

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

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

相关文章

单片机与PLC的区别有哪些?

单片机与PLC的区别有哪些? 什么是单片机&#xff1f; 单片机&#xff08;Microcontroller&#xff0c;缩写MCU&#xff09;是一种集成了中央处理器&#xff08;CPU&#xff09;、存储器和输入/输出接口等功能模块的微型计算机系统。它通常被用于嵌入式系统和控制系统中&#x…

怎样能实现不同服务器之间的文件实时同步?

数字化时代&#xff0c;数据已经成为企业的重要资产&#xff0c;其中文件共享是企业运行中的重要业务场景。由于办公文件可能存在不同服务器甚至不同的城市之间&#xff0c;企业文件的实时同步是很多中大型企业急需解决的问题&#xff0c;为了不耽误业务的运行&#xff0c;甚至…

WebSocket真实项目总结

websocket websocket是什么? websocket是一种网络通讯协议。 websocket 是HTML5开始提供的一种在单个TCP链接上进行全双工通讯的协议。 为什么需要websocket? 初次接触websocket&#xff0c;都会带着疑惑去学习&#xff0c;既然已经有了HTTP协议&#xff0c;为什么还需要另一…

千兆光模块和万兆光模块的安装和维护指南

光模块是网络通信中不可或缺的设备&#xff0c;安装和维护的重要性不能被忽视。本文将为您详细介绍千兆光模块和万兆光模块的安装和维护指南&#xff0c;帮助您更好地了解光模块的应用和维护技巧&#xff0c;从而为您的网络通信体验提供优质保障。 一、光模块简介 作为网络通…

CSS实现图片滑动对比

实现效果图如下&#xff1a; css代码&#xff1a; 知识点&#xff1a;resize: horizontal; 文档地址 <style>.image-slider {position: relative;display: inline-block;width: 500px;height: 300px;}.image-slider>div {position: absolute;top: 0;bottom: 0;left: …

有什么方法可以改善CRM实施投资回报?

数据统计显示&#xff0c;几乎70%以上CRM客户管理系统项目的投资回报是负数。这意味着超过半数的CRM项目的结果是失败的。那么我们有什么方法可以改善CRM实施投资回报吗&#xff1f;当然有&#xff0c;下面我们就来说一说。 如何改善CRM实施投资回报 首先&#xff0c;您选择的…

概念解析 | 费马路径

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:费马路径 费马路径: Fermat Path & 费马原理 背景介绍 在异质光学介质中,光线传播呈现出折射的行为。由于光速在不同介质中有所不同,光线在经过界面时,其路径也会发生偏转…

需要买哪些网络设备才能过等保?求解!

随着等保2.0的落地执行&#xff0c;越来越多的企业需要过等保。但不少企业都是第一次过等保&#xff0c;对于等保政策不是很了解&#xff0c;有小伙伴问&#xff0c;需要买哪些网络设备才能过等保&#xff1f;这里我们小编就给大家来简单回答一下&#xff0c;仅供参考哈&#x…

编程实例与解释,编程入门自学指南,中文编程工具下载

编程实例与解释&#xff0c;编程入门自学指南&#xff0c;中文编程工具下载。 编程实例可以点击最下方卡片了解&#xff0c;编程入门自学可以先从容易的入手&#xff0c;比如中文编程&#xff0c;先学习编程思路&#xff0c;然后再学习其他语言会比较轻松。中文编程工具可以下…

【java学习—十三】处理流之六:对象流(5)

文章目录 1. ObjectInputStream 和 OjbectOutputSteam2. 对象的序列化 假设有一个Person对象 把这个对象存到电脑的硬盘上&#xff0c;硬盘存储的基础是什么&#xff1f;&#xff08;二进制&#xff09;。那就需要把对象转化为一个二进制的字节流&#xff0c;把这个流保存到电脑…

园区网络项目实战

实验背景 某写字楼备搭建一张网络供楼内企业办公使用。写字楼共6层&#xff0c;目前已有三层投入使用&#xff0c;分别 是一层会客大厅、二层行政部及总经理办公室、三层研发部和市场部。一层设有核心机房&#xff0c;其 他各楼层均有一个小房间放置网络设备。 第一步 询…

出入库管理系统vue2前端开发服务器地址配置

【精选】vue.config.js 的完整配置&#xff08;超详细&#xff09;_vue.config.js配置_web学生网页设计的博客-CSDN博客 本项目需要修改两处&#xff1a; 1、vue开发服务器地址&#xff1a;config\index.js use strict // Template version: 1.3.1 // see http://vuejs-templa…

中国1024程序员节·上海站纪实

目录 前言 活动前奏 盛大开幕 技术交流与分享 彩蛋 游戏互动环节 番外篇&#xff1a;上海站活动安排 结束语 前言 1024 程序员节是专属开发者的节日&#xff0c;他们以“码”为梦&#xff0c;在技术世界中“程”风破浪。作为 2023 长沙中国 1024 程序员节的重要组成部分…

系统无法访问提示“配额不足无法处理此命令“的解决思路

一些老的电脑系统会出现 电脑系统出现无法访问C:Documents and SetAdministrator桌面&#xff0c;配额不足。 解决思路如下 1、电脑的开始菜单的工具栏&#xff0c;选择运行。 2、输入栏中写入命令“gpedit.msc”。 3、弹出组策略窗口&#xff0c;选择打开“计算机配置”—“…

2024郑州光伏展|郑州储能展|郑州国际太阳能光伏储能展览会

2024第四届中国&#xff08;郑州&#xff09;太阳能光伏及储能产业展览会 时间&#xff1a;2024年4月8-10日 地点&#xff1a;郑州.中原国际博览中心 随着人们对环境保护意识的不断提高&#xff0c;太阳能光伏和储能技术在能源领域的应用越来越广泛。为了更好地推广和应用太…

11-8 Spring入门

把Mybatis相关的内容怎么跟service进行调用&#xff0c;mybatis的底层全部由spring帮我创建 把之前所有的MybatisUtil全部干掉&#xff0c;以及我获取对象我都不自己new了&#xff0c;让Spring帮我做 Spring开始1 之前学的mybatis是用于解决一层的问题&#xff08;dao层&…

PDF翻页电子书制作教程,超简单噢~

PDF翻页电子书是一种可以在电脑、平板或手机上阅读的电子书&#xff0c;只要有网&#xff0c;可随时随地查看的&#xff0c;并且它还可以模拟真实的翻页效果&#xff0c;给读者展示出更好的阅读体验。那么&#xff0c;PDF翻页电子书如何制作呢&#xff1f; 其实制作这种PDF翻页…

SARAS算法

SARAS算法 代码仓库:https://github.com/daiyizheng/DL/tree/master/09-rl Sarsa算法是一种强化学习算法&#xff0c;用于解决马尔可夫决策过程&#xff08;MDP&#xff09;问题。它是一种基于值函数的方法&#xff0c;可以用于学习最优策略。本文将介绍Sarsa算法的流程。 S…

nginx 无法 停止

一、nginx正常停止命令 进入到nginx目录&#xff0c;然后执行 # 立即停止 nginx -s stop # 平滑停止 nginx -s quit 二、 如果你不小心启动了多次nginx.exe 那么通过任务管理器可以停止 三、如果 任务管理器无法停止 那么就在cmd命令中执行 netstat -ano //查看所以端口…

一文图解爬虫姊妹篇(spider)

—引导语 爬虫&#xff0c;没有一个时代比当前更重视它。一个好的爬虫似乎可以洞穿整个互联网&#xff0c;“来装满自己的胃”。 接上一篇&#xff1a;一文图解爬虫&#xff08;spider&#xff09; 博主已初步对爬虫的“五脏六腑”进行了解剖。虽然俗称“爬虫”&#xff0c;但窃…