SpringBoot整合多数据源的两种方式

⭐️作者简介:一个力求全干的Java后端开发者。
💗个人主页:CVcode码农的博客
👉当前专栏:SpringBoot整合篇
✔️本文内容:多数据源的配置,项目中如果需要使用多个数据源,可以直接cv
其他内容查看👇
      SpringBoot整合jdbc和开启事务


本人能力有限,如有遗漏或错误,敬请指正,谢谢

一、学习前提和项目结构

前提:需要掌握mybatis、mybatis-plus的使用和配置

数据库结构:在项目中同时使用这两个数据库

图1 数据库
图2 user表
图3 role表

二、mybatis方式配置多数据源

思路:根据自定义的配置数据源信息初始化数据源【不使用SpringBoot的配置自动注入数据源,因为这样只能配置一个数据源】

<!--druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.22</version>
        </dependency>
<!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.3.0</version>
        </dependency>

项目结构:
在这里插入图片描述

spring.datasource.db1.username=账号
spring.datasource.db1.password=密码
spring.datasource.db1.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.db1.jdbc-url=jdbc:mysql://localhost:3306/db1
spring.datasource.db1.type=com.alibaba.druid.pool.DruidDataSource

spring.datasource.db2.username=账号
spring.datasource.db2.password=密码
spring.datasource.db2.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.db2.jdbc-url=jdbc:mysql://localhost:3306/db2
spring.datasource.db2.type=com.alibaba.druid.pool.DruidDataSource

2.1配置第一个数据源

/**
 * @author zhenghs
 * @version 1.0
 * @description:
 * db1的数据源配置,@MapperScan先通过basePackages确认需要在哪个位置生成的mapper,
 * 再通过sqlSessionFactoryRef来确定动态代理生成的mapper是用的哪个数据源(sqlSessionFactory的作用可以去看mybatis部分)
 * @date 2022/12/29 11:56
 */
@Configuration
@MapperScan(basePackages = "com.hs.dao.db1",sqlSessionFactoryRef = "db1SqlSessionFactory")
public class DataSourceOneConfig {

    @Value("${spring.datasource.db1.jdbc-url}")
    private String url;
    @Value("${spring.datasource.db1.driverClassName}")
    private String driverClassName;
    @Value("${spring.datasource.db1.username}")
    private String username;
    @Value("${spring.datasource.db1.password}")
    private String password;

    //注入db1的数据源
    @Bean("db1dataSource")
    public DataSource dataSource1(){
        DruidDataSource druidDataSource=new DruidDataSource();
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        druidDataSource.setUrl(url);
        druidDataSource.setDriverClassName(driverClassName);
        return druidDataSource;
    }

    //注入由db1数据源的创建的sqlSessionFactory,不懂的可以看mybatis如何和spring整合
    @Bean("db1SqlSessionFactory")
    public SqlSessionFactory db1SqlSessionFactory(DataSource db1dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(db1dataSource);
        sqlSessionFactoryBean.setTypeAliasesPackage("com.hs.entity");
        org.apache.ibatis.session.Configuration configuration=new org.apache.ibatis.session.Configuration();
        configuration.setLogImpl(StdOutImpl.class);
        sqlSessionFactoryBean.setConfiguration(configuration);
        //扫描mapper的位置
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath*:mapper/db1/*.xml"));
        return sqlSessionFactoryBean.getObject();
    }

    //db1数据源的事务管理器
    @Bean("db1DataSourceTransactionManager")
    public DataSourceTransactionManager db1DataSourceTransactionManager(DataSource db1dataSource){
        DataSourceTransactionManager dataSourceTransactionManager=new DataSourceTransactionManager(db1dataSource);
        return dataSourceTransactionManager;
    }

    //这个作用和jdbcTemplate差不多,【但一般不用,可配可不配!】
    @Bean
    public SqlSessionTemplate db1SqlSessionTemplate(SqlSessionFactory db1SqlSessionFactory){
        SqlSessionTemplate sqlSessionTemplate=new SqlSessionTemplate(db1SqlSessionFactory);
        return sqlSessionTemplate;
    }

}

2.2配置第二个数据源

/**
 * @author zhenghs
 * @version 1.0
 * @description:
 * db2的数据源配置,@MapperScan先通过basePackages确认需要在哪个位置生成的mapper,
 * 再通过sqlSessionFactoryRef来确定动态代理生成的mapper是用的哪个数据源(sqlSessionFactory的作用可以去看mybatis部分)
 * @date 2022/12/29 11:56
 */
@Configuration
@MapperScan(basePackages = "com.hs.dao.db2",sqlSessionFactoryRef = "db2SqlSessionFactory") //动态代理生成
public class DataSourceTwoConfig {

    @Value("${spring.datasource.db2.jdbc-url}")
    private String url;
    @Value("${spring.datasource.db2.driverClassName}")
    private String driverClassName;
    @Value("${spring.datasource.db2.username}")
    private String username;
    @Value("${spring.datasource.db2.password}")
    private String password;

    //注入db2的数据源
    @Bean("db2dataSource")
    public DataSource dataSource2(){
        DruidDataSource druidDataSource=new DruidDataSource();
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        druidDataSource.setUrl(url);
        druidDataSource.setDriverClassName(driverClassName);
        return druidDataSource;
    }

    //注入由db2数据源的创建的sqlSessionFactory,不懂的可以看mybatis如何和spring整合
    @Bean("db2SqlSessionFactory")
    public SqlSessionFactory db2SqlSessionFactory(DataSource db2dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(db2dataSource);
        sqlSessionFactoryBean.setTypeAliasesPackage("com.hs.entity");
        org.apache.ibatis.session.Configuration configuration=new org.apache.ibatis.session.Configuration();
        configuration.setLogImpl(StdOutImpl.class);
        sqlSessionFactoryBean.setConfiguration(configuration);
        //扫描mapper的位置
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath*:mapper/db2/*.xml"));
        return sqlSessionFactoryBean.getObject();
    }

    //db2数据源的事务管理器
    @Bean("db2DataSourceTransactionManager")
    public DataSourceTransactionManager db2DataSourceTransactionManager(DataSource db2dataSource){
        DataSourceTransactionManager dataSourceTransactionManager=new DataSourceTransactionManager(db2dataSource);
        return dataSourceTransactionManager;
    }

    //这个作用和jdbcTemplate差不多,【但一般不用,可配可不配!】
    @Bean
    public SqlSessionTemplate db1SqlSessionTemplate(SqlSessionFactory db1SqlSessionFactory){
        SqlSessionTemplate sqlSessionTemplate=new SqlSessionTemplate(db1SqlSessionFactory);
        return sqlSessionTemplate;
    }
}

2.3测试查询

(实体类代码省略,代码已通过测试,可自行测试)

//这个由db1数据源动态代理生成bean
public interface UserMapper {

    User getUserById(int id);
}

//UserMapper.xml
<mapper namespace="com.hs.dao.db1.UserMapper">
    <select id="getUserById" resultType="com.hs.entity.User">
        select * from user where id=#{id}
    </select>
</mapper>
//这个由db2数据源动态代理生成bean
public interface RoleMapper {
    Role getRoleById(int id);
}

//RoleMapper.xml
<mapper namespace="com.hs.dao.db2.RoleMapper">
    <select id="getRoleById" resultType="com.hs.entity.Role">
        select * from role where id=#{id}
    </select>
</mapper>
@RestController
public class UserController {
    @Autowired
    private UserMapper userMapper;

    @RequestMapping("/user/{id}")
    public User getUserById(@PathVariable int id){
        User user = userMapper.getUserById(id);
        System.out.println(user);
        return user;
    }
}
@RestController
public class RoleController {
    @Autowired
    private RoleMapper roleMapper;

    @RequestMapping("/role/{id}")
    public Role getRoleById(@PathVariable int id){
        Role role = roleMapper.getRoleById(id);
        System.out.println(role);
        return role;
    }
}

三、 mybatis-plus方式配置多数据源

思路:原理使用的是aop,具体实现原理可看我另一篇文章,其他配置可看mybatis-plus官方文档mybatis-plus

ps:以下代码忽略mybatis-plus的mapper

<!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
<!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.22</version>
        </dependency>
<!--多数据源-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>

项目结构:
在这里插入图片描述

#设置默认的数据源,默认值即为master
spring.datasource.dynamic.primary=master
#严格匹配数据源,默认falsetrue:未匹配到指定数据源时抛异常 false:未匹配到则使用默认数据源
spring.datasource.dynamic.strict=false 
spring.datasource.dynamic.datasource.master.url=jdbc:mysql://localhost:3306/db1
spring.datasource.dynamic.datasource.master.username=root
spring.datasource.dynamic.datasource.master.password=123456
spring.datasource.dynamic.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver

#设置第二个数据源
spring.datasource.dynamic.datasource.slave.url=jdbc:mysql://localhost:3306/db2
spring.datasource.dynamic.datasource.slave.username=root
spring.datasource.dynamic.datasource.slave.password=123456
spring.datasource.dynamic.datasource.slave.driver-class-name=com.mysql.cj.jdbc.Driver

mybatis-plus.type-aliases-package=com.hs.entity

3.1快速开始

使用@DS(“库名”) 在方法或者类上切换数据源,如果在方法上没有添加@DS,那么默认在方法中使用的是默认数据源,也就是上面配置spring.datasource.dynamic.primary=master的master数据源

举例1:根据id查询user表数据,user表为db1数据库的一张表,上述配置中的master数据源

@RestController
public class TestController {
    @Autowired
    private UserMapper userMapper;
    
    //由于没有加@DS,那么使用默认数据源,也可以指定@DS("master")
    @RequestMapping("/user/{id}")
    public User getUserById(@PathVariable int id){
        User user = userMapper.selectById(id);
        System.out.println(user);
        return user;
    }
}

举例2:根据id查询role表数据,role表为db2数据库的一张表,上述配置中的slave数据源

@RestController
public class TestController {
    @Autowired
    private RoleMapper roleMapper;
    
    //指定slave数据源
    @DS("slave")
    @RequestMapping("/role/{id}")
    public Role getRoleById(@PathVariable int id){
        Role role = roleMapper.selectById(id);
        System.out.println(role);
        return role;
    }
}

举例3:手动切换数据源,在一个方法中,查询两个数据库。根据id查询user表和role表数据

@RestController
public class TestController {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RoleMapper roleMapper;

    @RequestMapping("/test/{id}")
    public String getDataById(@PathVariable int id){
    	//不指定现在默认使用的是master数据源
        User user = userMapper.selectById(id);
        //该方法作用是切换成slave数据源,只能有一个数据源,如果再添加,会替换之前的数据源
        DynamicDataSourceContextHolder.push("slave");
        Role role = roleMapper.selectById(id);
        System.out.println(user);
        System.out.println(role);
        //查看当前数据源
        System.out.println(DynamicDataSourceContextHolder.peek());
        //移除数据源,恢复master数据源
        DynamicDataSourceContextHolder.poll(); 
        return "success";
    }
}

3.2 DynamicDataSourceContextHolder解读

看源码得知,内部是由一个ThreadLocal来维护数据源的,也就是说手动切换数据源只在一个线程内有效,如果开一个新线程,那么数据源又变回默认数据源

在这里插入图片描述
验证如下:

@RestController
public class TestController {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RoleMapper roleMapper;
    
    @RequestMapping("/test")
    public String test(){
    	//使用默认数据源查询
        System.out.println(userMapper.selectList(null));
        //在当前线程切换到slave数据源
        DynamicDataSourceContextHolder.push("slave");
        
        //新启动一个线程,又恢复成默认数据源,role表在slave数据源中,所以此时查询会报错
        new Thread(() ->{
            System.out.println(roleMapper.selectList(null));
        }).start();
        
        return "success";
    }
}

在这里插入图片描述

四、总述

如果你的项目中使用的是mybatis,那么可以用上面这两种方式来操作多数据源
如果需要自己实现一个,那么需要使用AOP来实现,后续会出一篇文章《AOP动态切换数据源》

五、完整项目地址

完整项目地址

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
springboot可以通过使用dynamic-datasource-spring-boot-starter来实现多数据源整合。该启动器基于springboot,可以快速集成多个数据源。一般的思路是根据自定义的配置数据源信息初始化数据源,并使用druid连接池和mybatis进行相关配置。引用 具体步骤可以包括以下几个方面: 1. 引入相关依赖:在项目的pom.xml文件中添加dynamic-datasource-spring-boot-starter、druid-spring-boot-starter和mybatis-spring-boot-starter等依赖。引用 2. 配置数据源信息:在application.yml或application.properties文件中配置多个数据源的信息,包括数据库的连接地址、用户名、密码等。可以使用@ConfigurationProperties注解来绑定配置文件中的数据源信息到对应的实体类中。 3. 初始化数据源:使用Configuration类来初始化数据源。可以自定义一个DynamicDataSourceConfig类,并在其中使用@Bean注解来配置数据源。在该类中可以通过读取配置文件的方式来获取数据源信息,并将其初始化为对应的数据源。 4. 配置mybatis:在application.yml或application.properties文件中配置mybatis的相关信息,如mapper的扫描路径等。 通过以上步骤,就可以实现springboot多数据源整合。当然,以上只是一个基本的思路,具体实现还需要根据项目的实际需求进行调整和扩展。引用<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [SpringBoot实现多数据源两种方式](https://blog.csdn.net/m0_67401761/article/details/126114612)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [SpringBoot整合多数据源两种方式](https://blog.csdn.net/hongs468/article/details/128469985)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值