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

这篇具有很好参考价值的文章主要介绍了Spring Boot项目优雅实现读写分离。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


Spring Boot项目优雅实现读写分离,微服务架构设计,Java学习路线,spring boot,后端,java

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


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

Spring Boot作为一种快速开发框架,广泛应用于Java项目中。在一些大型应用中,数据库的读写分离是提升性能和扩展性的一种重要手段。本文将介绍如何在Spring Boot项目中优雅地实现读写分离,并通过适当的代码插入,详细展开实现步骤,同时进行拓展和分析。
Spring Boot项目优雅实现读写分离,微服务架构设计,Java学习路线,spring boot,后端,java

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学习路线,spring boot,后端,java

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


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

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

Spring Boot项目优雅实现读写分离,微服务架构设计,Java学习路线,spring boot,后端,java文章来源地址https://www.toymoban.com/news/detail-755058.html

到了这里,关于Spring Boot项目优雅实现读写分离的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Boot 优雅实现多租户架构,so easy~!

    多租户架构是指在一个应用中支持多个租户(Tenant)同时访问,每个租户拥有独立的资源和数据,并且彼此之间完全隔离。通俗来说,多租户就是把一个应用按照客户的需求“分割”成多个独立的实例,每个实例互不干扰。 更好地满足不同租户的个性化需求。 可以降低运维

    2024年02月09日
    浏览(41)
  • spring boot +Sa-Token优雅的实现项目鉴权!

    最近在做登录、授权的功能,一开始考虑到的是spring boot + spring security,但spring security太重,而我们是轻量级的项目,所以,spring security不适合我们。 而后考虑spring boot + shiro,但shiro自带的aop会影响spring boot的aop,所以,shiro也不适合我们。 后来浏览github时,发现Sa-Token这个框

    2024年02月06日
    浏览(49)
  • Spring Boot+Vue前后端分离项目如何部署到服务器

    🌟 前言 欢迎来到我的技术小宇宙!🌌 这里不仅是我记录技术点滴的后花园,也是我分享学习心得和项目经验的乐园。📚 无论你是技术小白还是资深大牛,这里总有一些内容能触动你的好奇心。🔍 🤖 洛可可白 :个人主页 🔥 个人专栏 :✅前端技术 ✅后端技术 🏠 个人

    2024年04月11日
    浏览(61)
  • spring boot+mybatis-plus配置读写分离

    对于mysql主从机制的读写分离,对于写操作写入主库,读取操作读取从库 一、安装依赖 二、配置文件配置数据源 三、在service,如果是读取操作的话,则需要加上注解@DS(“slave”)即可,可看如下示例

    2024年01月25日
    浏览(51)
  • 企业级实战 Spring Boot + K8S 中的滚动发布、优雅停机、弹性伸缩、应用监控、配置分离

    下面为大家介绍我司生产环境使用了3年的基于K8S的dev ops 配置实现 K8s + SpringCloud实现零宕机发版,优雅重启:健康检查+滚动更新+优雅停机+弹性伸缩+Prometheus监控+配置分离(镜像复用) 业务层面 项目依赖 pom.xml 使用 spring-boot-starter-actuator 镜像 存活、就绪检查 使用 prometheus

    2024年02月06日
    浏览(51)
  • “深入探究Spring Boot:实现微服务架构的利器“

    标题:深入探究Spring Boot:实现微服务架构的利器 摘要:本文将深入探讨Spring Boot作为实现微服务架构的利器。我们将介绍Spring Boot的特点、优势以及如何使用它来构建高效、可扩展的微服务应用。同时,我们还将通过示例代码演示如何使用Spring Boot创建一个简单的微服务应用

    2024年02月16日
    浏览(43)
  • Java之Spring Boot+Vue+Element UI前后端分离项目,前端插件化主流框架和实现原理

    三、设置Axios发起请求统一前缀的路径 https://code100.blog.csdn.net/article/details/123302546 1、HelloWorld.vue getInfo() { this.$http.get(‘blog/queryBlogByPage?title=’ + this.title + ‘page=’ + this.page + ‘rows=’ + this.rows) .then(response = ( this.info = response.data, this.total = this.info.total, this.totalPage = this.info.tota

    2024年04月16日
    浏览(65)
  • Spring Boot如何实现微服务架构中的API网关?

    随着微服务架构的流行,越来越多的企业开始构建自己的微服务系统。在这种情况下,API网关变得尤为重要。API网关是微服务架构中的一个组件,它可以帮助我们管理和路由所有的API请求。Spring Boot提供了一些工具和框架,可以帮助我们轻松地实现API网关。在本文中,我们将

    2024年02月07日
    浏览(65)
  • Spring Boot进阶(73):Spring Boot如何优雅地使用Feign进行服务间通信?

            在分布式系统中,服务间通信是非常常见的情况。而Feign就是一个开源的Java HTTP客户端,可以帮助我们在Spring Boot应用中快速构建和使用HTTP客户端,方便实现服务间的通信。本文将介绍如何优雅地使用Feign进行服务间通信。         那么,具体如何实现呢?这将又

    2024年02月06日
    浏览(54)
  • 使用 System.exit() 来优雅地终止 Spring Boot 项目

    😊 @ 作者: 一恍过去 💖 @ 主页: https://blog.csdn.net/zhuocailing3390 🎊 @ 社区: Java技术栈交流 🎉 @ 主题: 使用 System.exit() 来优雅地终止 Spring Boot 项目 ⏱️ @ 创作时间: 2023年09月04日 System.exit(): System.exit() 方法是 Java 中用于退出程序的方法。它接受一个整数参数,通常被用

    2024年02月09日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包