springboot多数据源切换原理,springboot动态配置多数据源

  springboot多数据源切换原理,springboot动态配置多数据源

  概述在日常业务开发项目中,将只配置一组数据源。如果需要从其他系统获取数据,通常可以通过调用接口来访问,或者通过kettle等第三方工具将数据同步到自己的数据库中。

  但是也会有在项目中需要引用多个数据源的情况。例如,以下场景:

  自主开发的数据迁移系统至少需要两套数据源,一套旧的,一套旧的。从旧的读取数据写入新的会增加系统流量,降低单个的响应效率。引入读写分离方案,写数据是一个数据源。读取数据是另一个数据源环境描述Spring BootmysqlmyBatis-plus Spring-AOP项目目录结构控制器:存储接口类服务:存储服务类映射器:映射器接口实体用于存储操作数据库:存储数据库表实体类vo:存储视图类conte返回前端Xt:存储并保存当前线程数据源键类常量:存储并定义数据源键常量类config:存储数据源配置类注释:存储动态数据源注释AOP:存储动态数据source annotation section class resources . config:项目配置文件resources.mapper:数据库xml文件key类描述忽略controller/service/entity/mapper/XML的介绍。

  属性:数据源配置文件。虽然可以配置成Spring boot的默认配置文件application.properties/application.yml文件,但是如果数据源比较多,根据实际使用情况,最好的配置方式是独立配置。DynamicDataSourceConfig:数据源配置类DynamicDataSource:动态数据源配置类DataSourceRouting:动态数据源批注DynamicDataSourceAspect:动态数据源设置配置文件DynamicDataSourceContextHolder:当前线程持有的数据源keyDataSourceConstants:数据源key constant类的开发过程

  动态数据源过程Spring Boot的动态数据源本质上是在一个地图中存储多个数据源。需要使用数据源时,可以从地图中获取进行处理。

  在Spring中,已经提供了抽象类AbstractioningDataSource来实现这个功能。只需继承AbstractioningDataSource类并覆盖其determineCurrentLookupKey()方法,该方法只需返回数据源键,即数据源映射的键。

  所以我们在实现动态数据源的时候,只需要继承它,实现自己获取数据源的逻辑就可以了。AbstractRoutingDataSource在顶层继承DataSource,所以也可以作为数据源对象,所以在项目中作为主数据源使用。

  AbstractioningDataSource的原理AbstractioningDataSource中有一个重要的属性:

  TargetDataSources:目标数据源,即在项目开始时设置的、需要AbstractRoutingDataSource管理的数据源。DefaultTargetDataSource:默认数据源,项目启动时设置的默认数据源。如果没有指定数据源,将返回默认数据源。ResolvedDataSources:它也是一个存储数据源,在处理targetDataSources之后存储。你可以看看源代码。

  ResolvedDefaultDataSource:默认数据源处理两次,源代码是上图中最后两行代码。AbstractRoutingDataSource中的所有方法和属性:

  更重要的是determineTargetDataSource方法。

  受保护的数据源determineTargetDataSource(){

  assert . not null(this . resolved data sources,“数据源路由器未初始化”);

  object lookup key=determineCurrentLookupKey();

  data source data source=this . resolveddatasources . get(lookup key);

  if(data source==null(this . loottfallback lookup key==null)){

  data source=this . resolveddefaultdata source;

  }

  if (dataSource==null) {

  引发新的IllegalStateException(无法确定查找键[ lookupKey ])的目标数据源;

  }

  返回数据源;

  }

  /**

  *确定当前的查找关键字。这通常是

  *实现以检查线程绑定的事务上下文。

  * p允许任意键。归还的钥匙需要

  *匹配存储的查找键类型,由

  * { @ link # resolveSpecifiedLookupKey }方法。

  */

  @Nullable

  受保护的抽象对象determineCurrentLookupKey();这个方法主要就是返回一个数据源对象,主要逻辑就是先通过方法determineCurrentLookupKey获取一个目标对象的lookupKey,然后通过这个查询到已解析数据源中获取数据源(已解决的数据源就是一个地图,上面已经提到过了);如果没有找到数据源,就返回默认的数据源determineCurrentLookupKey .就是程序员配置动态数据源需要自己实现的方法。

  问题配置多数据源后启动项目报错:需要属性" sqlSessionFactory "或“sqlSession模板”。

  翻译过来就是:需要属性" sqlSessionFactory "或sqlSessionTemplate。也就是说注入数据源的时候需要这两个数据,但是这两个属性在启动容器中没有找到。

  当引入mybatis-plus依赖mybatis-plus启动程序后,会添加一个自动配置类MybatisPlusAutoConfiguration。其中有两个方法sqlSessionFactory()、sqlSessionTemplate()。这两个方法就是给容器中注入" sqlSessionFactory "或" sqlSessionTemplate "两个属性。

  @配置(

  proxyBeanMethods=false

  )

  @ condition alon类({ sqlsessionfactory。class,SqlSessionFactoryBean.class})

  @ conditionalonsinglectant(数据源。类)

  @ EnableConfigurationProperties({ mybatissplusproperties。class })

  @ auto configure after({数据源自动配置。类,mybatispluslanguagedriverautoconfiguration。class })

  公共类MybatisPlusAutoConfiguration实现初始化Bean {

  @Bean

  @ ConditionalOnMissingBean

  公共SQL session factory SQL session factory(数据源)引发异常{

  MybatisSqlSessionFactoryBean factory=new MybatisSqlSessionFactoryBean();

  factory.setDataSource(数据源);

  工厂。设置VFS(春季开机VFS。类);

  if(字符串实用程序。hastext(这个。属性。getconfiglocation()){

  工厂。setconfiglocation(this。资源加载器。获取资源(这。属性。getconfiglocation()));

  }

  this . apply配置(工厂);

  如果(这个。属性。getconfigurationproperties()!=null) {

  工厂。setconfigurationproperties(this。属性。getconfigurationproperties());

  }

  如果(!对象实用程序。isempty(这个。拦截器){

  工厂。设置插件(这个。拦截器);

  }

  if (this.databaseIdProvider!=null) {

  工厂。setdatabaseidprovider(this。databaseidprovider);

  }

  if(字符串实用程序。haslength(这个。属性。gettypealiasespackage()){

  工厂。settypealiasespackage(this。属性。gettypealiasespackage());

  }

  如果(这个。属性。gettypealiasessupertype()!=null) {

  工厂。settypealiasessupertype(this。属性。gettypealiasessupertype());

  }

  if(字符串实用程序。haslength(这个。属性。gettypehandlerspackage()){

  工厂。settypehandlerspackage(this。属性。gettypehandlerspackage());

  }

  如果(!对象实用程序。isempty(这个。类型处理程序)){

  工厂。settype处理程序(this。类型处理程序);

  }

  如果(!对象实用程序。isempty(这个。属性。resolvemapperlocations()){

  工厂。setmapperlocations(this。属性。resolvemapperlocations());

  }

  Objects.requireNonNull(工厂);

  这个。getbean then(事务工厂。class,factory:setTransactionFactory);

  班级?扩展语言驱动defaultLanguageDriver=this。属性。getdefaultscriptinglanguagedriver();

  如果(!对象实用程序。isempty(这个。语言驱动程序)){

  工厂。setscriptinglanguagedrivers(this。语言驱动);

  }

  可选var 10000=可选。可空的(defaultLanguageDriver);

  Objects.requireNonNull(工厂);

  var 10000。如果存在(factory:setDefaultScriptingLanguageDriver);

  这个。applysqlsessionfactorybean定制程序(工厂);

  全局配置全局配置=this。属性。getglobalconfig();

  对象。要求非空(全局配置);

  这个。getbean then(metaobjecthandler。类,全局配置:setMetaObjectHandler);

  这个。getbeansthen(ikey生成器。第一类

  globalConfig.getDbConfig().设定键发电机(一);

  });

  对象。要求非空(全局配置);

  这个。getbean then(isql注入器。类,全局配置:setsql注入器);

  对象。要求非空(全局配置);

  这个。getbean then(标识符生成器。类,全局配置:setidentifier生成器);

  工厂。setglobalconfig(全局配置);

  返回工厂。getobject();

  }

  @Bean

  @ ConditionalOnMissingBean

  公共SqlSessionTemplate SqlSessionTemplate(SqlSessionFactory SqlSessionFactory){

  执行者类型执行者类型=this。属性。获取执行器类型();

  返回executorType!=null?new SqlSessionTemplate(sqlSessionFactory,执行人类型):new SqlSessionTemplate(sqlSessionFactory);

  }

  } 这里主要关注配置类上面的注解,详细如下:

  @配置(

  proxyBeanMethods=false

  )

  //当类路径下有SqlSessionFactory.class、SqlSessionFactoryBean.class时才生效

  @ condition alon类({ sqlsessionfactory。class,SqlSessionFactoryBean.class})

  //容器中只能有一个符合条件的数据源

  //因为容器中有3个数据源,且没有指定主数据源,这个条件不通过,就不会初始化这个配置类了

  @ conditionalonsinglectant(数据源。类)

  @ EnableConfigurationProperties({ mybatissplusproperties。class })

  @ auto configure after({数据源自动配置。类,mybatispluslanguagedriverautoconfiguration。class })

  公共类MybatisPlusAutoConfiguration实现初始化Bean {

  }因为MybatisPlusAutoConfiguration不满足@ conditionalonsinglectant(数据源。类)条件,所以自动配置不会生效,就不会执行sqlSessionFactory()、sqlSessionTemplate()两个方法。容器中就不会有sqlSessionFactory、sqlSessionTemplate两个豆对象,因此会报错。

  所以在数据源配置类中的动态数据源配置上添加@主要注解即可。

  @配置

  @ property source( class path:config/JDBC。属性’)

  @ mapper扫描(基础包={ com。新兴。学习。数据来源。映射器 })

  公共类动态数据源配置{

  @Bean

  @主要

  公共数据源dynamicDataSource(){

  地图对象,对象目标数据源=new HashMap();

  目标数据源。put(数据源常量.DS_KEY_MASTER,主数据源());

  目标数据源。put(数据源常量.DS_KEY_SLAVE,从数据源());

  动态数据源data source=新动态数据源();

  数据来源。settargetdata sources(目标数据源);

  数据来源。setdefaulttargetdata source(主数据源());

  返回数据源;

  }

  }

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: