Spring | 基于SpringBoot的多数据源实战 - 使用seata实现多数据源的全局事务管理

Spring | 基于SpringBoot的多数据源实战 - 使用seata实现多数据源的全局事务管理

  • 引言
      • 1.1 多数据源的必要性
      • 1.2 多数据源的应用场景
  • 实战演示
    • 2.1 创建实体类
    • 2.2 配置数据源
    • 2.3 实现数据源配置类
    • 2.4 配置Repository类
    • 2.5 运行与验证
  • 事务管理与数据一致性
      • 3.1 事务管理
      • 3.2 使用Seata完成全局事务管理
        • 3.2.1 安装seata-server
        • 3.2.2 配置IDEA
  • 总结
  • 参考文献

引言

在软件开发中,多数据源的应用越来越普遍,特别是在微服务架构业务模块化的场景下。多数据源能够让不同的业务模块和微服务拥有各自独立的数据存储,大大提高了系统的灵活性和可维护性。本文将深入探讨多数据源的配置和实施,以及在Spring Boot环境下,如何通过Spring Data JPAGradle来实现多数据源的管理和应用。

本文讨论的多数据源指的是关系型数据库,即一个服务有多个这样的数据库。

1.1 多数据源的必要性

随着业务的发展和演变,单一数据源已经无法满足多元化和复杂化的业务需求多数据源的应用不仅能够更好地支持业务的发展,还能够有效地实现资源隔离和管理,减少系统的耦合度,提高服务的稳定性和可用性。使用多数据源可以有如下几个优点:

  1. 性能优化:不同的关系型数据库有各自的优势和特性,一些数据库更适合取操作,而另一些数据库更适合入操作。通过将读写负载分配到不同的数据库实例上,可以优化性能。
  2. 数据隔离:在一个系统中,有些数据可能更重要,需要更高的安全性和可靠性;而其他数据可能不太重要,可以容忍一定程度的数据丢失。这个时候,将不同类型的数据存储在不同的数据库中,可以实现数据的隔离,满足不同的数据安全和可靠性需求。
  3. 业务逻辑隔离:在复杂的系统中,不同的模块或子系统可能有不同的业务逻辑和数据处理需求。为不同的模块或子系统使用不同的数据库,可以简化系统的设计和维护。

1.2 多数据源的应用场景

常见到的几个大型项目的业务场景如下:

  • 金融系统:金融系统通常要处理大量的事务数据和报表数据。将事务处理和报表生成分配到不同的数据库可以优化性能和简化系统设计。
  • 电商平台:电商平台通常会涉及到用户信息、订单数据、商品数据等多种类型的数据。为这些不同类型的数据使用不同的数据库实例可以实现数据和业务逻辑的隔离
  • ERP系统:企业资源规划(ERP)系统通常包含多个模块,例如财务、人力资源和供应链管理。为每个模块使用独立的数据库可以使得开发和维护更加便捷。

以下所有示例均已上传至Github上,大家可以将项目拉取到本地进行运行
Github示例(如果对Gradle还不熟练,建议翻看我之前的文章):gradle-spring-boot-demo


实战演示

本章将详细说明如何在Spring Boot项目中实施多数据源。我们会一步一步地演示如何配置两个H2数据库实例作为我们的数据源。

2.1 创建实体类

首先,我们创建两个实体类,一个用于主数据源,一个用于次数据源。我们在这里以User实体为例。请确保您的实体类在正确的包中。

// 主数据源实体
@Entity
@Data
@Table(name = "users")
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;private String email;
}// 次数据源实体
@Entity
@Table(name = "orders")
@Data
public class Order {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String orderNumber;private Double amount;
}

2.2 配置数据源

接下来,我们需要在application.yml中配置两个数据源:

spring:datasource:primary:jdbc-url: jdbc:h2:file:./multi-datasource/data/testdb1driver-class-name: org.h2.Driverusername: sapassword: passwordsecondary:jdbc-url: jdbc:h2:file:./multi-datasource/data/testdb2driver-class-name: org.h2.Driverusername: sapassword: passwordh2:console:enabled: truejpa:hibernate:ddl-auto: updateshow-sql: true

这里,我们配置了两个H2数据库实例,一个作为主数据源,一个作为次数据源。

2.3 实现数据源配置类

为了实现多数据源,我们需要创建两个配置类,PrimaryDataSourceConfigSecondaryDataSourceConfig,并在其中定义DataSourceEntityManagerFactoryTransactionManager的beans。

@Configuration
@EnableJpaRepositories(basePackages = "org.kfaino.datasource.repository.primary")
@EntityScan(basePackages = {"org.kfaino.datasource.entity.primary"})
public class PrimaryDataSourceConfig {@Primary@Bean(name = "primaryDataSource")@ConfigurationProperties(prefix = "spring.datasource.primary")public DataSource primaryDataSource() {return DataSourceBuilder.create().build();}@Primary@Bean(name = "entityManagerFactory")public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(EntityManagerFactoryBuilder builder,@Qualifier("primaryDataSource") DataSource dataSource) {return builder.dataSource(dataSource).packages("org.kfaino.datasource.entity.primary") // 设置实体类的包路径.persistenceUnit("primary").properties(hibernateProperties()).build();}private Map<String, Object> hibernateProperties() {Map<String, Object> properties = new HashMap<>();properties.put("hibernate.hbm2ddl.auto", "update");properties.put("hibernate.show_sql", true);return properties;}@Primary@Bean(name = "transactionManager")public PlatformTransactionManager transactionManager(@Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {return new JpaTransactionManager(entityManagerFactory);}}@Configuration
@EnableJpaRepositories(basePackages = "org.kfaino.datasource.repository.secondary",entityManagerFactoryRef = "secondaryEntityManagerFactory",transactionManagerRef = "secondaryTransactionManager")
@EntityScan(basePackages = {"org.kfaino.datasource.entity.primary"})
public class SecondaryDataSourceConfig {@Bean(name = "secondaryDataSource")@ConfigurationProperties(prefix = "spring.datasource.secondary")public DataSource secondaryDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "secondaryEntityManagerFactory")public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(EntityManagerFactoryBuilder builder,@Qualifier("secondaryDataSource") DataSource dataSource) {return builder.dataSource(dataSource).packages("org.kfaino.datasource.entity.secondary") // 设置实体类的包路径.persistenceUnit("secondary").properties(hibernateProperties()).build();}private Map<String, Object> hibernateProperties() {Map<String, Object> properties = new HashMap<>();properties.put("hibernate.hbm2ddl.auto", "update");properties.put("hibernate.show_sql", true);return properties;}@Bean(name = "secondaryTransactionManager")public PlatformTransactionManager secondaryTransactionManager(@Qualifier("secondaryEntityManagerFactory") EntityManagerFactory secondaryEntityManagerFactory) {return new JpaTransactionManager(secondaryEntityManagerFactory);}}

💡 温馨提示: 请注意,在这个配置类中,我们为两个数据源分别定义了DataSourceEntityManagerFactoryTransactionManager@Primary注解用于指定主数据源相关的beans。

2.4 配置Repository类

我们需要创建两个Repository类,每个类操作一个数据源的实体。在这里,我们可以使用Spring Data JPA的JpaRepository接口。

// 主数据源Repository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {}// 次数据源Repository
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {}

2.5 运行与验证

运行Spring Boot应用,在控制台能够看到两个数据源都被成功配置。
在这里插入图片描述
并且可以通过相应的Repository类进行数据操作。我们写个Controller来和数据库进行交互,限于篇幅,其它代码我已省略,如需完整实例,可以直接从GitHub仓库下载:

@RestController
@RequestMapping("user")
public class UserController {@Resourceprivate UserService userService;@Resourceprivate OrderService orderService;@Resourceprivate UserOrderService userOrderService;@PostMapping("/createUser")public User createUser(@Valid @RequestBody UserDTO userDTO) {return userService.createUser(userDTO);}@PostMapping("/createOrder")public Order createOrder(@Valid @RequestBody OrderDTO orderDTO) {return orderService.createOrder(orderDTO);}@PostMapping("/createMix")public User createMix(@Valid @RequestBody UserOrderDTO userOrderDTO) {return userOrderService.createUserAndOrder(userOrderDTO);}
}

接着执行这三个请求:
在这里插入图片描述
两张不同数据源的表均被创建完毕:
在这里插入图片描述
在这里插入图片描述

💡 注意: 在进行实际的数据操作时,如果需要特定的事务管理器,可以在Service类或Repository类上使用@Transactional(transactionManager = "指定的事务管理器")来进行指定。


事务管理与数据一致性

3.1 事务管理

在多数据源中,事务管理是至关重要的,它确保我们的系统在执行多个操作时能够维持数据的完整性和一致性。我们用代码演示一个案例,我们在UserOrderService中故意写一个会报错代码:

    @Transactional("transactionManager")public User createUserAndOrder(UserOrderDTO userOrderDTO) {OrderDTO orderDTO = new OrderDTO();BeanUtils.copyProperties(userOrderDTO, orderDTO);orderService.createOrder(orderDTO);// 报错int i = 1/0;User user = new User();BeanUtils.copyProperties(userOrderDTO, user);userRepository.save(user);return user;}

我们调用下该方法:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

由于使用的是不同的事务管理器,尽管transactionManager事务管理器回滚了,我们依然可以看到orders表被提交:
在这里插入图片描述

3.2 使用Seata完成全局事务管理

💡本节案例只是简单的全局事务管理,为了演示测试方便,除了seata本身并未引入其它中间件

3.2.1 安装seata-server

要想使用seata需要先安装seata-server,下载路径如下:https://github.com/seata/seata/releases 我这里使用的是window系统,下载zip即可:
在这里插入图片描述
下载后双击运行:
在这里插入图片描述
在控制台看到seata正常启动了:
在这里插入图片描述

3.2.2 配置IDEA
  1. 引入seata依赖,我这里使用的是gradle,只需要引入这行即可:

        implementation 'io.seata:seata-spring-boot-starter:1.7.1' // 请检查最新的版本号
    
  2. 新增application.yml配置

    seata:enabled: trueapplication-id: multi-datasourcetx-service-group: my_test_tx_groupenable-auto-data-source-proxy: trueconfig:type: filefile:data-file: classpath:file.confregistry:type: filefile:data-file: classpath:registry.conf
    
  3. 新增file.conf文件

    service {# tx-service-group映射vgroupMapping.my_test_tx_group = "default"vgroupMapping.default = "default"# Seata Server的地址,是你的Seata Server所在的IP地址和端口default.grouplist = "127.0.0.1:8091"# 其他相关配置enableDegrade = falsedisableGlobalTransaction = false
    }store {mode = "file"file {# 本地事务日志存储的目录dir = "sessionStore"}
    }
  4. 新增registry.conf文件

    registry {type = "file"file {name = "file.conf"}
    }config {type = "file"file {name = "file.conf"}
    }
  5. UserOrderService新增如下方法:

        @GlobalTransactionalpublic void createUserAndOrderByGlobalTransaction(UserOrderDTO userOrderDTO) {OrderDTO orderDTO = new OrderDTO();BeanUtils.copyProperties(userOrderDTO, orderDTO);orderService.createOrder(orderDTO);// 报错int i = 1/0;UserDTO userDTO = new UserDTO();BeanUtils.copyProperties(userOrderDTO, userDTO);userService.createUser(userDTO);}
    
  6. 新增controller方法:

        @PostMapping("/createMixGlobalTransaction")public void createMixByGlobalTransaction(@Valid @RequestBody UserOrderDTO userOrderDTO) {userOrderService.createUserAndOrderByGlobalTransaction(userOrderDTO);}
    
  7. 请求controller
    在这里插入图片描述
    执行结果如下:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    全局事务生效,事务被回滚。


总结

至此,本章结束。本文深入探讨了多数据源的优势和应用常见,并为你展示了在Spring Boot如何进行多数据源的使用和整合。同时,我们也探讨了多数据源中存在的事务问题,并通过seata的全局事务管理解决这个问题。

参考文献

  1. SpringBoot如何整合多个数据源,看这篇就够了 - 腾讯云
  2. Spring Boot 整合多数据源,这才叫优雅 - 掘金
  3. springboot整合mybatis跨库操作、配置多个数据源DataSource - CSDN
  4. SpringBoot整合MyBatis多数据源 - 腾讯云
  5. 5分钟学会springboot整合多数据源 - 思否
  6. springboot(七):springboot+mybatis多数据源最简解决方案 - 阿里云

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

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

相关文章

变电站无人值守方案:提升效率与增强安全性

随着信息技术、人工智能、大数据的发展进步&#xff0c;电力行业正逐步向智能化转型。其中&#xff0c;无人值守变电站成为了现代电力系统的明显趋势。这种新型的运营模式不仅提高了效率&#xff0c;还极大地增强了电力系统的安全性。 无人值守变电站的核心概念是在没有人类现场…

Adams齿轮副

1.运动副 添加旋转副的时候&#xff0c;必须先物体后公共part(即此处的ground&#xff09;&#xff0c;最后再选择质心点 2.啮合点 啮合点marker的z轴必须是齿轮分度圆的切线方向 3.啮合点 两齿轮的旋转副&#xff0c;和啮合点&#xff0c;即cv marker &#xff0c;必须属…

win10打开VMware 16 pro里面的虚拟机就蓝屏怎么办

2023年9月30日&#xff0c;周六下午 今天下午我也遇到了这个问题&#xff0c;后来解决了&#xff0c;于是记录一下我的解决办法 目录 1、打开控制面板&#xff0c;并选择“程序和功能” 2、点击“启动或关闭Windows服务” 3、勾选两个服务 4、重启电脑&#xff0c;大功告成…

【CMU15-445 Part-14】Query Planning Optimization I

Part14-Query Planning & Optimization I SQL is Declarative&#xff0c;只告诉想要什么而不需要说怎么做。 IBM System R是第一个实现query optimizer查询优化器的系统 Heuristics / Rules 条件触发 静态规则&#xff0c;重写query来remove 低效或者愚蠢的东西&#xf…

牛客 ( 计算几何

#include <bits/stdc.h> using namespace std; using ll long long; using PII pair<double , double>; int n; PII p[3000010]; vector<PII> pp; PII yuan(PII a , PII b , PII c) {//已知三个点确定圆的半径和圆心double x1 a.first,x2 b.first,x3 c.…

华为云云耀云服务器L实例评测 | 实例评测使用之体验评测:华为云云耀云服务器管理、控制、访问评测

华为云云耀云服务器L实例评测 &#xff5c; 实例评测使用之体验评测&#xff1a;华为云云耀云服务器管理、控制、访问评测 介绍华为云云耀云服务器 华为云云耀云服务器 &#xff08;目前已经全新升级为 华为云云耀云服务器L实例&#xff09; 华为云云耀云服务器是什么华为云云耀…

协议-TCP协议-基础概念02-TCP握手被拒绝-内核参数-指数退避原则-TCP窗口-TCP重传

协议-TCP协议-基础概念02-TCP握手被拒绝-TCP窗口 参考来源&#xff1a; 《极客专栏-网络排查案例课》 TCP连接都是TCP协议沟通的吗&#xff1f; 不是 如果服务端不想接受这次握手&#xff0c;它会怎么做呢&#xff1f; 内核参数中与TCP重试有关的参数(两个) -net.ipv4.tc…

asp.net企业生产管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net 企业生产管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语 言开发 二、功能介绍 (1)用户管理&…

索尼 toio™应用创意开发征文|检测工业平台震动

虽然索尼toio Q宝机器人主要是为儿童教育娱乐开发的&#xff0c;但我认为它在工业等领域也有一定应用潜力。例如&#xff0c;工业领域经常会有某些平面在实际作业中持续震动&#xff0c;导致零件过疲劳、平台失去稳定等问题。而这样的平台往往位于机器内部&#xff0c;从外部很…

TensorFlow学习1:使用官方模型进行图片分类

前言 人工智能以后会越来越发达&#xff0c;趁着现在简单学习一下。机器学习框架有很多&#xff0c;这里觉得学习谷歌的 TensorFlow&#xff0c;谷歌的技术还是很有保证的&#xff0c;另外TensorFlow 的中文文档真的很友好。 文档&#xff1a; https://tensorflow.google.cn/…

云安全【阿里云ECS攻防】

关于VPC的概念还请看&#xff1a;记录一下弹性计算云服务的一些词汇概念 - 火线 Zone-安全攻防社区 一、初始化访问 1、元数据 1.1、SSRF导致读取元数据 如果管理员给ECS配置了RAM角色&#xff0c;那么就可以获得临时凭证 如果配置RAM角色 在获取ram临时凭证的时候&#xff…

ubuntu安装PhotoPrism,并开启安卓照片同步

之前安装了黑群晖7.2&#xff0c;并开启了Photo&#xff0c;照片同步用的挺好。唯一的缺陷是群晖的照片搜索太弱鸡了&#xff0c;基本上关键字搜索是一点不可用&#xff0c;常见的“花”&#xff0c;“山”&#xff0c;“文件”&#xff0c;“证件”都是不可用的。 后来了解到了…

Ubuntu基于Docker快速配置GDAL的Python、C++环境

本文介绍在Linux的Ubuntu操作系统中&#xff0c;基于Docker快速配置Python、C等不同编程语言均可用的地理数据处理库GDAL的方法。 首先&#xff0c;我们访问GDAL库的Docker镜像官方网站&#xff08;https://github.com/OSGeo/gdal/tree/master/docker&#xff09;。其中&#x…

DAMA-DMBOK2重点知识整理CDGA/CDGP——第14章 大数据与数据科学

目录 一、分值分布 二、重点知识梳理 1、引言 1.1 业务驱动因素 1.2 原则 1.3 基本理念 2、活动 2.1 定义大数据战略和业务需求 2.2 选择数据源 2.3 获得和接收数据源 2.4 制定数据假设和方法 2.5 集成和调整数据进行分析 2.6 使用模型探索数据 2.7 部署和监控 …

Android 遍历界面所有的View

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、实践四、 推荐阅读 一、导读 我们…

FFmpeg 命令:从入门到精通 | ffmpeg 命令分类查询

FFmpeg 命令&#xff1a;从入门到精通 | ffmpeg 命令分类查询 FFmpeg 命令&#xff1a;从入门到精通 | ffmpeg 命令分类查询ffmpeg -versionffmpeg -buildconfffmpeg -formatsffmpeg -muxersffmpeg -demuxersffmpeg -codecsffmpeg -decodersffmpeg -encodersffmpeg -bsfsffmpeg…

【QT】使用toBase64方法将.txt文件的明文变为非明文(类似加密)

目录 0.环境 1.背景 2.详细代码 2.1 .h主要代码 2.2 .cpp主要代码&#xff0c;主要实现上述的四个方法 0.环境 windows 11 64位 Qt Creator 4.13.1 1.背景 项目需求&#xff1a;我们项目中有配置文件&#xff08;类似.txt&#xff0c;但不是这个格式&#xff0c;本文以…

信息安全:网络安全漏洞防护技术原理与应用.

信息安全&#xff1a;网络安全漏洞防护技术原理与应用. 网络安全漏洞又称为脆弱性&#xff0c;简称漏洞。漏洞一般是致使网络信息系统安全策略相冲突的缺陷&#xff0c;这种缺陷通常称为安全隐患。 安全漏洞的影响主要有机密性受损、完整性破坏、可用性降低、抗抵赖性缺失、可…

Java | Maven(知识点查询)

文章目录 Maven知识速查1. Maven概述2. Maven的作用3. Maven的下载4. Maven的环境配置5. Maven 的基础组成5.1 Maven仓库5.1.1 本地仓库配置&#xff1a;5.1.2 中央仓库配置&#xff1a;5.1.3 镜像仓库配置 5.2 Maven坐标 6. Maven项目6.1 手工创建Maven项目6.2 自动构建项目 7…

【C++】map、set,multiset和multimap的使用及底层原理【完整版】

目录 一、map和set的使用 1、序列式容器和关联式容器 2、set的使用讲解 3、map的使用讲解 二、multiset和multimap 1、multiset和multimap的使用 2、OJ题&#xff1a;前k个高频单词 一、map和set的使用 1、序列式容器和关联式容器 序列式容器&#xff1a;vector/list/s…