SpringBoot多数据源读写分离的自定义配置问题及解决方法

  1. 背景介绍

Spring Boot 是一种基于 Spring 框架的快速开发 Web 应用的微服务框架,它的设计能够使开发者极速创建可独立运行的 Spring 应用程序。而在实际的开发过程中,很多业务场景需要使用多个数据源,并且多个数据源的读写分离也是一种非常常见的数据存储方案,这时候就需要对 Spring Boot 进行多数据源配置。

  1. Spring Boot 多数据源配置

在 Spring Boot 中实现多数据源配置可以通过以下步骤:

(1)引入相关依赖。

<!--mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.21</version>
</dependency>
<!--Druid连接池-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.5</version>
</dependency>

(2)在 application.yml 文件中进行数据源配置。

spring:
  datasource:
    master:
      url: jdbc:mysql://localhost:3306/test?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver
    slave1:
      url: jdbc:mysql://localhost:3307/test?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver

(3)自定义多数据源配置类。

@Configuration
public class DataSourceConfig {
    @Bean(name = "masterDataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DruidDataSource masterDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "slaveDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.slave1")
    public DruidDataSource slaveDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "dynamicDataSource")
    @Primary
    public DynamicDataSource dynamicDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
                                               @Qualifier("slaveDataSource") DataSource slaveDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceType.MASTER.getType(), masterDataSource);
        targetDataSources.put(DataSourceType.SLAVE.getType(), slaveDataSource);

        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource); //默认数据源
        dynamicDataSource.setTargetDataSources(targetDataSources);

        return dynamicDataSource;
    }
}

(4)自定义数据源持有类。

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceHolder.getDataSource();
    }
}

(5)定义数据源类型枚举类。

public enum DataSourceType {
    MASTER("master"),
    SLAVE("slave");

    private String type;

    DataSourceType(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }
}

(6)定义数据源 Holder 类,用于在线程中存储数据源类型的信息。

public class DataSourceHolder {
    /**
     * 使用ThreadLocal将数据源与当前线程绑定
     */
    private static final ThreadLocal<String> holder = new ThreadLocal<>();

    /**
     * 绑定数据源
     */
    public static void putDataSource(String dataSource) {
        holder.set(dataSource);
    }

    /**
     * 获取当前绑定的数据源
     */
    public static String getDataSource() {
        return holder.get();
    }

    /**
     * 清除绑定的数据源信息
     */
    public static void clear() {
        holder.remove();
    }
}

(7)在 Service 层的方法上加上数据源注解,注明该方法使用哪个数据源。

@Service
@Slf4j
public class UserInfoServiceImpl implements UserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    /**
     * 使用主库进行写操作
     */
    @DataSource(value = DataSourceType.MASTER)
    @Override
    public int addUserInfo(UserInfo userInfo) {
        return userInfoMapper.insertSelective(userInfo);
    }

    /**
     * 使用从库进行读操作
     */
    @DataSource(value = DataSourceType.SLAVE)
    @Override
    public UserInfo getUserInfoById(String id) {
        return userInfoMapper.selectByPrimaryKey(id);
    }
}
  1. 示例说明

以下是两个示例,分别是对主库进行写操作和对从库进行读操作。

(1)向主库中插入一条用户信息。

@PostMapping("/addUser")
public String addUser(@RequestBody UserInfo userInfo) {
    try {
        userInfoService.addUserInfo(userInfo);
        return "添加成功!";
    } catch (Exception e) {
        e.printStackTrace();
        return "添加失败!";
    }
}

(2)从从库中查询一条用户信息。

@GetMapping("/getUser/{id}")
public UserInfo getUser(@PathVariable("id") String id) {
    try {
        return userInfoService.getUserInfoById(id);
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}
  1. 总结

通过以上步骤,我们即可轻松地实现 Spring Boot 的多数据源配置,实现读写分离,提高系统的并发能力和稳定性。需要注意的是,在实际的开发中,我们还需考虑到数据源的负载均衡、事务管理、多数据源切换等问题,需要在实际的生产环境中根据需求进行进一步的配置和调整。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot多数据源读写分离的自定义配置问题及解决方法 - Python技术站

(0)
上一篇 2023年5月18日
下一篇 2023年5月18日

相关文章

  • ToroDB和Yanza的区别

    ToroDB和Yanza都是开源的分布式数据库系统,但它们有一些不同之处。 数据库类型 ToroDB支持关系型数据库PostgreSQL,它将PostgreSQL转换为分布式数据库系统,以便于在多个节点上进行数据存储和处理。而Yanza则是一个基于键值存储的NoSQL数据库系统,它采用了分布式哈希表技术来管理分布式数据。 数据复制方式 ToroDB使用流式复…

    database 2023年3月27日
    00
  • MySQL基本架构与锁的知识点有哪些

    本篇内容主要讲解“MySQL基本架构与锁的知识点有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“MySQL基本架构与锁的知识点有哪些”吧! MySql架构 SQL Layer Connection Pool : 连接池,用于接收连接请求和管理连接。 ManagementService&Utilitie…

    2023年4月8日
    00
  • 详解Redis连接命令使用方法

    Redis连接命令是用来连接Redis数据库的命令,包括连接,认证和关闭连接三个命令。 在本篇文章中,我们将详细讲解Redis连接命令的完整攻略,包括: 使用连接命令连接到Redis数据库 使用认证命令认证Redis连接 使用关闭命令关闭Redis连接 接下来我们将逐一讲解。 使用连接命令连接到Redis数据库 Redis连接命令有两种方式:通过Redis客…

    Redis 2023年3月18日
    00
  • 如何在Python中插入MongoDB数据库中的数据?

    以下是在Python中插入MongoDB数据库中的数据的完整使用攻略。 使用MongoDB数据库的前提条件 在使用Python连接MongoDB数据库之前,确保已经安装了MongoDB数据库,并已经创建使用数据库和集合,同时需要安装Python的驱动,例如pymongo。 步骤1:导入模块 在Python中使用pymongo模块连接MongoDB数据库。以下…

    python 2023年5月12日
    00
  • Openstack 使用migrate进行数据库升级实现方案详细介绍

    Openstack 使用migrate进行数据库升级实现方案详细介绍 简介 Openstack是一个开放源代码的云计算软件平台,其中涉及到的各种组件和服务都需要对应的数据存储支持。在不同的版本之间,组件的数据存储模式可能发生变化,此时就需要进行数据库升级。其中,常用的数据库升级工具之一就是migrate。 本文将详细介绍Openstack使用migrate进…

    database 2023年5月22日
    00
  • 如何使用Python将数据插入到数据库中?

    在Python中,可以使用多种方式将数据插入到数据库中,包括使用标准库中的sqlite3模块、使用第三方库如pymysql、psycopg2等。以下是使用sqlite3模块和pymysql库将插入到数据库中的完整攻略: 使用sqlite3模块将数据插入到数据库中 sqlite3模块是Python标准库中的一个模块,用于与SQLite数据库进行交互。以下是使用…

    python 2023年5月12日
    00
  • SQL Server中的游标介绍

    关于“SQL Server中的游标介绍”完整攻略,我将分为以下几个部分进行详细讲解: 游标是什么? SQL Server中如何声明和使用游标? 游标的类型和使用场景 示例说明 总结 接下来,我将对每个部分进行逐一介绍: 1. 游标是什么? 游标(Cursor)是一种在 SQL Server 中通过编程实现的数据访问方式,它是通过在内存中开辟一块存储区,使得程…

    database 2023年5月21日
    00
  • MySQL单表千万级数据处理的思路分享

    我会根据“MySQL单表千万级数据处理的思路分享”的主题,来分享一些本人的见解和经验,再通过两个示例来说明问题。 1. 准备工作 在开始讲解之前,首先准备好MySQL的环境和数据集。环境可以使用Docker等快速搭建,数据集可以挑选一些像京东、淘宝等大型数据集进行测试。 2. 数据库性能优化 2.1 使用索引 索引可以大大提高查询效率。需要注意的是,优化索引…

    database 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部