springboot mapper无法注入_搞定!用多套源策略解决SpringBoot多数据源

本文介绍了在SpringBoot中处理多数据源的场景,通过创建独立的数据源配置,实现主从数据库的读写分离。详细讲解了如何搭建Spring Boot+MyBatis Plus工程,配置多套数据源,包括数据源连接信息、配置文件、实体、Mapper操作等,并分析了多数据源的优缺点。
摘要由CSDN通过智能技术生成

1. 引言

在开发过程中,避免不了需要同时操作多个数据库的情况,通常的应用场景如下 :

  • 数据库高性能场景:主从,包括一主一从,一主多从等,在主库进行增删改操作,在从库进行读操作。
  • 数据库高可用场景:主备,包括一往一备,多主多备等,在数据库无法访问时可以切换。
  • 同构或异构数据的业务处理:需要处理的数据存储在不同的数据库中,包括同构(如都是 MySQL ),异构(如一个MySQL ,另外是 PG 或者 Oracle )。

使用 Spring Boot 该如何处理多个数据库的读写,一般有以下几种策略:

  • 多套数据源:即针对一个数据库建立一套数据处理逻辑,每套数据库都包括数据源配置、会话工厂( sessionFactory )、连接、SQL 操作、实体。各套数据库相互独立。
  • 动态数据源:确定数量的多个数据源共用一个会话工厂,根据条件动态选取数据源进行连接、SQL 操作。
  • 参数化变更数据源:根据参数添加数据源,并进行数据源切换,数据源数量不确定。通常用于对多个数据库的管理工作。

本系列文章“搞定SpringBoot多数据源”将针对以上几个策略进行描述,本文是第一篇:“多套数据源”,主要以主从场景为实例,结合代码,对多套数据源的实现进行描述,内容包括搭建 Spring Boot + MyBatis Plus 工程、多数据源配置、多数据源处理与使用逻辑。

本文所涉及到的示例代码:https://github.com/mianshenglee/my-example/tree/master/multi-datasource,读者可结合一起看。

2. 运行环境

  • JAVA 运行环境: JDK1.8
  • Spring Boot: 2.2.2.RELEASE
  • MyBatis Plus: 3.3.0
  • 开发IDE: IDEA
  • 构建工具Maven: 3.3.9
  • MySQL : 5.6.26
  • Lombok: 1.18.10

3. 多套数据源

多套数据源,顾名思义每一个数据库有一套独立的操作。从下往上,数据库、会话工厂、DAO操作,服务层都是独立的一套,如下所示:

f78bbc0ce9e3019ce30fa11f3508dea6.png

本示例中,以一主一从两个数据库,两数据库的分别有一个表 test_user,表结构一致,为便于说明,两个表中的数据是不一样的。两个表结构可在示例代码中的 sql 目录中获取。

3.1 搭建 Spring Boot 工程

3.1.1 初始化 Spring Boot 工程

使用 spring.io构建初始 Spring Boot 工程,选用以下几个构件:

  • Lombok: 用于简化操作
  • Spring Configuration Processor:配置文件处理器
  • Spring Web: 用于构建web服务
  • MySQL Driver: 数据库驱动

3.1.2 添加 MyBatis Plus 依赖

MyBatis Plus 是对 MyBatis 增强,简化 DAO 操作,提高数据库操作效率。依赖如下:

com.baomidou    mybatis-plus-boot-starter    3.3.0

3.1.3 添加包结构

主要添加以下几个包:

├─config ---------------------------------- // 数据源配置├─controller ------------------------------ // web服务├─entity ---------------------------------- // 实体类│ ├─master │ └─slave ├─mapper ---------------------------------- // dao操作类│ ├─master │ └─slave └─vo -------------------------------------- // 视图返回对象  

注:

由于示例简单,省略service层 实体类及mapper均根据主从进行划分

3.2 多套数据源

3.2.1 独立数据库连接信息

Spring Boot 的默认配置文件是 application.properties ,由于有两个数据库配置,独立配置数据库是好的实践,因此添加配置文件 jbdc.properties ,添加以下自定义的主从数据库配置:

# masterspring.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.master.jdbc-url=jdbc:mysql://localhost:3306/mytest?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF-8spring.datasource.master.username=rootspring.datasource.master.password=111111# slavespring.datasource.slave.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.slave.jdbc-url=jdbc:mysql://localhost:3306/my_test1?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF-8spring.datasource.slave.username=rootspring.datasource.slave.password=111111

3.2.2 多套数据源配置

有了数据源连接信息,需要把数据源注入到 Spring 中。由于每个数据库使用独立的一套数据库连接,数据库连接使用的 SqlSession 进行会话连接,SqlSession 是由SqlSessionFactory 生成。因此,需要分别配置SqlSessionFactory 。以下操作均在 config 目录 下:

(1)添加 DataSourceConfig 配置文件,注入主从数据源

@Configuration@PropertySource("classpath:config/jdbc.properties")public class DatasourceConfig {    @Bean("master")    @ConfigurationProperties(prefix = "spring.datasource.master")    public DataSource masterDataSource(){        return DataSourceBuilder.create().build();    }    @Bean("slave")    @ConfigurationProperties(prefix = "spring.datasource.slave")    public DataSource slaveDataSource(){        return DataSourceBuilder.create().build();    }}

注解 PropertySource 指定配置信息文件 注解 ConfigurationProperties 指定主从配置前缀 分别指定主从数据源的 bean 名称为 master ,slave

(2)添加 MasterMybatisConfig 配置文件,注入 Master 的SqlSessionFactory

@Configuration@MapperScan(basePackages = "me.mason.demo.basicmultidatasource.mapper.master", sqlSessionFactoryRef = "masterSqlSessionFactory")public class MasterMybatisConfig {    /**     * 注意,此处需要使用MybatisSqlSessionFactoryBean,不是SqlSessionFactoryBean,     * 否则,使用mybatis-plus的内置函数时就会报invalid bound statement (not found)异常     */    @Bean("masterSqlSessionFactory")    public SqlSessionFactory masterSqlSessionFactory(@Qualifier("master") DataSource dataSource) throws Exception {        // 设置数据源        MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();        mybatisSqlSessionFactoryBean.setDataSource(dataSource);        //mapper的xml文件位置        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();        String locationPattern = "classpath*:/mapper/master/*.xml";        mybatisSqlSessionFactoryBean.setMapperLocations(resolver.getResources(locationPattern));        //对应数据库的entity位置        String typeAliasesPackage = "me.mason.demo.basicmultidatasource.entity.master";        mybatisSqlSessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage);        return mybatisSqlSessionFactoryBean.getObject();    }}

注解 MapperScan 指定那些包下的 mapper 使用本数据源,并指定使用哪个SqlSessionFactory,注意,此处的 sqlSessionFactoryRef 即本配置中的注入的 SqlSessionFactory。 设置指定的数据源,此处是名为 master 的数据源,使用 Qualifier 指定。 MyBatis Plus 对应的 Mapper 若有自定义的 mapper.xml, 则使用 setMapperLocations 指定。 若需要对实体进行别名处理,则使用 setTypeAliasesPackage 指定。

(3)添加 SlaveMybatisConfig 配置文件,注入Slave 的 SqlSessionFactory

与(2)一致,把 master 改为 slave即可。

3.2.3 多套实体

在 MyBatis 配置中,实体设置 typeAliases 可以简化 xml 的配置,前面提到,使用 typeAliasesPackage 设置实体路径,在 entity 包下分别设置 master 和 slave 包,存放两个库对应的表实体,使用 Lombok 简化实体操作。如下:

@Data@TableName("test_user")public class MasterTestUser implements Serializable {    private static final long serialVersionUID = 1L;    /** id */    private Long id;    /** 姓名 */    private String name;    ...}

3.2.4 多套Mapper操作

在 mapper 包下,分别添加 master 和 slave 包,存放两个库对应的 Mapper ,由于 MyBatis Plus 本身已包含基本的 CRUD 操作,所以很多时候可以不用 xml 文件配置。若需要自定义操作,需要结合 xml文件,与此同时需要指定对应的 xml 文件所在目录。如下:

@Repositorypublic interface MasterTestUserMapper extends BaseMapper {    /**     * 自定义查询     * @param wrapper 条件构造器     */    List selectAll(@Param(Constants.WRAPPER)Wrapper wrapper);}

slave对应的Mapper与此类似

3.2.5 多套 mapper xml 文件

MyBatis Plus 的默认mapper xml 文件路径为 classpath*:/mapper/**/*.xml,即 resources/mapper 下,同样设置 master 及 slave 目录,分别存放对应的mapper xml 文件。以下是 master 的自定义操作:

        select * from test_user                  ${ew.customSqlSegment}        

3.3 多数据源使用

经过上面的多套数据源配置,可知道,若需要操作哪个数据库,直接使用对应的 mapper 进行 CRUD 操作即可。如下为 Controller 中分别查询两个库,获取到的数据合在一起返回:

@RestController@RequestMapping("/user")public class TestUserController {    @Autowired    private MasterTestUserMapper masterTestUserMapper;    @Autowired    private SlaveTestUserMapper slaveTestUserMapper;    /**     * 查询全部     */    @GetMapping("/listall")    public Object listAll() {        //master库,自定义接口查询        QueryWrapper queryWrapper = new QueryWrapper<>();        List resultData = masterTestUserMapper.selectAll(queryWrapper.isNotNull("name"));        //slave库,mp内置接口        List resultDataSlave = slaveTestUserMapper.selectList(null);        //返回        Map result = new HashMap<>();        result.put("master" , resultData);        result.put("slave" , resultDataSlave);        return ResponseResult.success(result);    }}

使用Autowired注解注入对应的mapper 使用对应数据库的 mapper 进行业务操作 根据业务在数据库中执行相应的操作,如主只做增删改操作、从只读操作

至此,多数据源的实现已完成,当前示例是两个同构的数据库,当然,若是异构的数据库,或者多于两个的数据库,处理方式是一样的,只不过是把数据源增加一套而已。

4. 优缺点

由上述说明,我们可以总结一下使用多套数据源的方法进行多数据库操作,它的优缺点是什么。

4.1 优点

  • 简单、直接:一个库对应一套处理方式,很好理解。
  • 符合开闭原则( OCP ):开发的设计模式告诉我们,对扩展开放,对修改关闭,添加多一个数据库,原来的那一套不需要改动,只添加即可。

4.2 缺点

  • 资源浪费:针对每一个数据源写一套操作,连接数据库的资源也是独立的,分别占用同样多的资源。SqlSessionFactory 是一个工厂,建议是使用单例,完全可以重用,不需要建立多个,只需要更改数据源即可,跟多线程,使用线程池减少资源消耗是同一道理。
  • 代码冗余:在前面的多数据源配置中可以看出,其实 master 和 slave 的很多操作是一样的,只是改个名称而已,因此会造成代码冗余。
  • 缺乏灵活:所有需要使用的地方都需要引入对应的mapper,对于很多操作,只是选择数据源的不一样,代码逻辑是一致的。另外,对于一主多从的情况,若需要对多个从库进行负载均衡,相对比较麻烦。

正因为有上述的缺点,所以还有改进的空间。于是就有了动态数据源,至于动态数据源如何实现,下回分解。

5. 总结

本文对多个数据库的操作进行了初步探讨,并对使用多套源的策略进行讲解,结合主从代码示例,搭建了 Spring Boot + MyBatis Plus 工程,配置多数据源及使用 Mapper 进行多数据源操作,最后对多套数据源的优缺点进行总结。希望小伙伴们可以对多数据源操作有个初步印象。

本文有配套的示例代码,有兴趣的可以跑一下示例来感受一下。

参考资料

  • Spring主从数据库的配置和动态数据源切换原理: https://www.liaoxuefeng.com/article/1182502273240832
  • 多数据源与动态数据源的权衡: https://juejin.im/post/6844903661655572494
  • 谈谈Spring Boot 数据源加载及其多数据源简单实现: https://juejin.im/post/6844903817260056589
  • Spring Boot 和 MyBatis 实现多数据源、动态数据源切换: https://juejin.im/post/6844903566717485069


作者:mason技术记录
链接:https://juejin.cn/post/6844904047158411277
来源:掘金

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值