SpringBoot配置双数据源(一个项目同时连接操作两台数据库)

2023-11-04

前言:

近期公司要上线3.0版本,需要将2.0的数据迁移到3.0中继续沿用,由于3.0的数据库相比2.0.的数据库改动很大,最主要的是2.0数据库的主键为自然数自增主键,而3.0数据库的主键为UUID2,所以只能使用程序动态迁移!

声明:

本教程使用的持久化框架为JPA,所以数据源也是基于JPA。采用的是SpringBoot2 + SpringDataJPA + MySQL + 双数据源!

一、双数据源的适用场景:

1、主从库分离(数据库读写分离)

2、数据迁移

3、系统版本升级,数据库升级到另外一款

二、application.yml中配置

spring:
  jpa:
    hibernate:
      ddl-auto: create
      naming:
        physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
        implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
    open-in-view: true
    show-sql: true
    generate-ddl: true


  datasource: #database
    primary:  # 3.0 Datasource
      jdbc-url: jdbc:mysql://127.0.0.1:3306/gtu?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
      username: root
      password: 123456

    secondary:  # 2.0 Datasource
      jdbc-url: jdbc:mysql://127.0.0.1:3306/gtu-not-completed?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
      username: root
      password: 123456

注:配置文件中需要指定两个数据源,这里在配置的时候是没有自动提示的,因为这是我们自定义的,需要在程序中动态读取。

三、读取application.yml配置的两个数据源,并将其注入到Spring的IOC容器中

@Configuration
public class DataSourceConfig {


    @Bean(name = "primaryDataSource")
    @Qualifier("primaryDataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "secondaryDataSource")
    @Qualifier("secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

}

注解解释:

@Configuration:SpringBoot启动将该类作为配置类,同配置文件一起加载

@Bean:将该实体注入到IOC容器中

@Qualifier:指定数据源名称,与Bean中的name属性原理相同,主要是为了确保注入成功

@Primary:指定主数据源

@ConfigurationProperties:将配置文件中的数据源读取进到方法中,进行build

四、以类的方式配置两个数据源

(1)主数据源(对应DataSourceConfig类中的primaryDataSource)

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactoryPrimary",
        transactionManagerRef = "transactionManagerPrimary",
        basePackages = {"com.gtcloud.repository"})    // 指定该数据源操作的DAO接口包
public class PrimaryConfig {

    @Autowired
    @Qualifier("primaryDataSource")
    private DataSource primaryDataSource;

    @Primary
    @Bean(name = "entityManagerPrimary")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
    }

    @Primary
    @Bean(name = "entityManagerFactoryPrimary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(primaryDataSource)
                .properties(getVendorProperties())
                .packages("com.gtcloud.model")         //设置实体类所在位置
                .persistenceUnit("primaryPersistenceUnit")
                .build();
    }

    private Map getVendorProperties() {
        HashMap<String, Object> properties = new HashMap<>();
        properties.put("hibernate.dialect",
                env.getProperty("hibernate.dialect"));
        properties.put("hibernate.ddl-auto",
                "create");
        properties.put("hibernate.physical_naming_strategy",
                "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
        properties.put("hibernate.implicit_naming_strategy",
                "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
        return properties;
    }

    @Autowired
    private Environment env;

    @Primary
    @Bean(name = "transactionManagerPrimary")
    public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
    }

}

 

(2)从(次)数据源

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactorySecondary",
        transactionManagerRef = "transactionManagerSecondary",
        basePackages = {"com.gtmove.repository"}) //设置DAO接口层所在包位置
public class SecondaryConfig {

    @Autowired
    @Qualifier("secondaryDataSource")
    private DataSource secondaryDataSource;

    @Bean(name = "entityManagerSecondary")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactorySecondary(builder).getObject().createEntityManager();
    }

    @Bean(name = "entityManagerFactorySecondary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(secondaryDataSource)
                .properties(getVendorProperties())
                .packages("com.gtmove.model")        //设置实体类所在包的位置
                .persistenceUnit("primaryPersistenceUnit")
                .build();
    }

    private Map getVendorProperties() {
        HashMap<String, Object> properties = new HashMap<>();
        properties.put("hibernate.hbm2ddl.auto",
                env.getProperty("hibernate.hbm2ddl.auto"));
        properties.put("hibernate.ddl-auto",
                env.getProperty("update"));
        properties.put("hibernate.dialect",
                env.getProperty("hibernate.dialect"));
        properties.put("hibernate.physical_naming_strategy",
                "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
        properties.put("hibernate.implicit_naming_strategy",
                "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
        return properties;
    }

    @Autowired
    private Environment env;

    @Bean(name = "transactionManagerSecondary")
    PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
    }
}

这两个类主要配置每个数据源,包括事务管理器、以及实体管理器等配置。

注:必须要指定DAO接口所在的包以及实体类所在的包。每个数据源主要操作它指定的资源(DAO接口CURD、实体类)

五、注意点:

1、SpringBoot启动类必须关闭 --程序启动加载的仓库(@EnableJpaRepositories),因为在数据源配置类中已经开启了。如果没有去掉,程序会跑不起来!

@SpringBootApplication(scanBasePackages = {""})  // 指定加载程序主包,存在默认值【可选】
//@EntityScan({""})
//@EnableJpaRepositories(basePackages = {""})
public class Gt3datamoverApplication {

    public static void main(String[] args) {
        SpringApplication.run(Gt3datamoverApplication.class, args);
    }

}

2、如果需要对数据源连接的表进行DDL(正向生成表、程序启动动态更新表),需要在PrimaryConfig类中 / SecondaryConfig类中的getVendorProperties()方法中进行手动设置(此教程都已设置好了!)

六、在整合双数据源有问题的,欢迎加博主QQ:1402218191 !

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringBoot配置双数据源(一个项目同时连接操作两台数据库) 的相关文章

随机推荐

  • Github注册中,邮箱验证通不过解决办法

    使用谷歌注册的时候 验证收不到消息 1 注册出现如图问题 2 在注册失败的页面 点返回的箭头 点了之后不要动 3 然后进入开启一个新的页面 复制下面的链接 进去页面 可能有点慢 等一等 OctoCaptchahttps octocaptch
  • python爬虫的学习总结

    背景 基于django框架完成jira网页数据的爬取 由于对爬虫知识知道的太少 我开始了新的学习之旅 本文前半部分都是记录这一周主要的错误 如果想直接看最终成果 可以跳到本文 成功爬取 部分浏览 学习爬虫知识 在知道了本项目可能需要爬虫后
  • C语言求解由1,2,3,4,四位数字构成的互不相同且无重复数字的四位数

    采用多重循环的方式即可 首先明确一共有四个数字供选择 组成的是四位数 那么在个 十 百 千的取值上 就只能有一位是1 一位是2 一位是3 一位是4 代码如下 include
  • 【Rust】2、实战:文件、网络、时间、进程-线程-容器、内核、信号-中断-异常

    文章目录 七 文件和存储 7 2 serde 与 bincode 序列化 7 3 实现一个 hexdump 7 4 操作文件 7 4 1 打开文件 7 4 2 用 std fs Path 交互 7 5 基于 append 模式实现 kv数据
  • 2023-9-14 最长公共子序列

    题目链接 最长公共子序列 include
  • oracle导出后 ascii编码转utf-8问题

    1 在设置如下环境变量后 从oracle中导出的中文字符为乱码 export NLS LANG AMERICAN AMERICA ZHS16GBK 2 在Linux上用file i命令查看 编码格式如下 xy w2 backimage tx
  • Mybatis-plus动态条件查询QueryWrapper的使用

    Mybatis plus动态条件查询QueryWrapper的使用 一 queryWrapper介绍 queryWrapper是mybatis plus中实现查询的对象封装操作类 可以封装sql对象 包括where条件 order by排序
  • 【Shell牛客刷题系列】SHELL6 去掉空行:来学习字符转换工具——tr命令

    该系列是基于牛客Shell题库 针对具体题目进行查漏补缺 学习相应的命令 刷题链接 牛客题霸 Shell篇 该系列文章都放到专栏下 专栏链接为 专栏 Linux 欢迎关注专栏 本文知识预告 首先学习了批量字符转换 压缩 删除的文本工具tr命
  • v-model的理解

    原理 1 展示 父组件v model 子组件接受一个props值value 将它展示到子组件自己的input上 2 改变 当子组件自身发生改变时 触发自身的input方法 然后触发父组件的事件方法 改变父组件的vaule 进而改变接受的pr
  • python作业(4)

    5 2 更多地条件测试 代码如下 str1 AAAA str2 BBBB str3 AAAA print str1 str2 str str1 str2 print str1 str3 str str1 str3 num1 10 num2
  • 蓝桥杯单片机14届记录 + 6-13届省赛代码+试题

    客观题 01 一个 8 位的 DAC 转换器 供电电压为 3 3V 参考电压 2 4V 其 1LSB 产生的输出电 压增量是 V A 0 0129 B 0 0047 C 0 0064 D 0 0094 02 IAP15F2K61S2 单片机
  • 编程实现古诗词填空

    编程实现古诗词填空登鹳雀楼 在屏募上品示 楼船 夜雪瓜洲渡 秋风大散关 请用户将缺失的汉宇 铁马 填入空白处 并在屏幕上显示完整的古诗词 楼船夜雪瓜洲渡 铁马秋风大散关
  • Java实现LRU算法

    文章目录 1 内存空间有限 当缓存满的时候 如何淘汰缓存 2 实现LRU demo 1 使用Java容器LinkedHashMap 2 哈希表 HashMap 双向链表 1 内存空间有限 当缓存满的时候 如何淘汰缓存 FIFO First
  • 【Linux】RPM软件包和Yum软件仓库、apt

    RPM 简介 RPM Package Manager RPM 包管理器 由红帽公司提出 Redhat SUSE 等系列采用 建立集中数据库 记录软件包安装 卸载等变化信息 分析软件包依赖关系 RPM 包 文件名特征 软件名 版本信息 操作系
  • 10种简单的Java性能优化学习

    10种简单的Java性能优化学习 你是否正打算优化hashCode 方法 是否想要绕开正则表达式 Lukas Eder介绍了很多简单方便的性能优化小贴士以及扩展程序性能的技巧 最近 全网域 Web Scale 一词被炒得火热 人们也正在通过
  • 多层目录编译的makefile文件编写

    一直想自己做一个目录结构稍复杂一点的makefile 看make的manual上写的有点不好理解 再从网上搜搜也没有发现比较好的教程 我是个搞工程的 懂点计算 也没有受过专业编程训练 对于一些技术不是很懂 有时想使用也会不知到如何下手 找不
  • Mysql 管理

    目录 0 课程视频 1 系统数据库 gt 安装完mysql gt 自带四个数据库 2 常用工具 gt 写脚本用 2 1 mysql 客户端工具 2 2 mysqladmin 2 3 mysqlbinlog gt 二进制日志 gt 运维讲解
  • UI架构相关

  • 锐捷网管系统漏洞利用分析

    利用此漏洞可获取后台密码 现在复现 1 fofa搜索 title RG UAC登录页面 body admin 2 现在 查看源代码 向下拉看到这个 就是密码 3 MD5解密 登录成功
  • SpringBoot配置双数据源(一个项目同时连接操作两台数据库)

    前言 近期公司要上线3 0版本 需要将2 0的数据迁移到3 0中继续沿用 由于3 0的数据库相比2 0 的数据库改动很大 最主要的是2 0数据库的主键为自然数自增主键 而3 0数据库的主键为UUID2 所以只能使用程序动态迁移 声明 本教程