数据库读写分离

为什么数据库需要配置读写分离f

   在数据库层面实现读写分离,就是配置一个Master数据库,多个Slave数据库,Master负责保存数据和读取实时数据,Slave主要读取非实时性的数据。
   在数据库读写操作中,读的频率远远大于写,并且读取操作所占用的资源和耗时也更多,所以把读写分离,可有效的缓解数据库的压力。

实现的原理

   实现的原理主要分为两种:

        1.静态的选择Master/Slave数据库(通过单独配置读写库,在方法中已经写死使用读库或者写库)

        2.数据库选择是动态切换(这里写的是这种方式实现读写分离)

   动态获取连接的流程:

         ps:我们的ReadWriteDataSourceConfig需要继承于AbstractRoutingDataSource

        1.AbstractRoutingDataSource初始化会依赖注入配置文件中你所配置的DataSource, 并保存于Map中(结构为key-DataSource,其中key为配置文件中设置的,key是为了标识对应的数据库,后续动态获取时会从ThreadLocal中获取key)

        2.通过aop拦截注解DBReadOnly(自定义),readDataSource的key保存于ThreadLocal中。

        3.获取数据库链接时,AbstractRoutingDataSource会调用覆写的getConnetion,其中getConnetion方法会调用determineTargetDataSource方法,它会调用抽象方法determineCurrentLookupKey(目的就是为了获取对应保存数据库的Map的key),我们的ReadWriteDataSourceConfig需要覆写determineCurrentLookupKey方法,返回ThreadLocal中的key(如果Key不存在,会使用默认库,下面会详细介绍),从而AbstractRoutingDataSource会去获取对应的数据库连接,实现动态获取数据库连接。

 

实现的原理:

   动态切换实现的原理主要是使用了annotation, Spring aop 等技术,在应用获取数据库连接时动态给于Master/Slave的connection,要实现它我们需要继承AbstractRoutingDataSource。
   
   
   可以看到AbstractRoutingDataSource是继承于AbstractDataSource类的,AbstractDataSource是实现的DataSource的接口
/**
   * <p>Attempts to establish a connection with the data source that
   * this {@code DataSource} object represents.
   *
   * @return  a connection to the data source
   * @exception SQLException if a database access error occurs
   * @throws java.sql.SQLTimeoutException  when the driver has determined that the
   * timeout value specified by the {@code setLoginTimeout} method
   * has been exceeded and has at least tried to cancel the
   * current database connection attempt
   */
  Connection getConnection()  throws  SQLException;
    这是DataSource的抽象方法,最终获取数据库连接就是通过这个方法,最终的核心步骤就是去覆写getConnetion方法,让它去创建我们对应读写库的连接。
 
    我们的ReadWriteDataSourceConfig是继承于AbstractRoutingDataSource的,AbstractRoutingDataSource是去覆写了getConnetion的,但是在看getConnetion之前我们需要看另一段代码
     public  abstract  class  AbstractRoutingDataSource  extends  AbstractDataSource  implements  InitializingBean{
 
 
     private  Map<Object, Object> targetDataSources; //保存对应key的DataSource
 
     private  Object defaultTargetDataSource; //默认的使用的DataSource的Bean
 
     private  boolean  lenientFallback =  true ;
 
     private  DataSourceLookup dataSourceLookup =  new  JndiDataSourceLookup();
 
     private  Map<Object, DataSource> resolvedDataSources; //所有DateSource保存于这个Map中
 
     private  DataSource resolvedDefaultDataSource; //默认使用的DataSource,下面会详谈
 
 
     @Override
     public  void  afterPropertiesSet() {
         if  ( this .targetDataSources ==  null ) {
             throw  new  IllegalArgumentException( "Property 'targetDataSources' is required" );
         }
         this .resolvedDataSources =  new  HashMap<Object, DataSource>( this .targetDataSources.size());
         for  (Map.Entry<Object, Object> entry :  this .targetDataSources.entrySet()) { //这是
             Object lookupKey = resolveSpecifiedLookupKey(entry.getKey());
             DataSource dataSource = resolveSpecifiedDataSource(entry.getValue());
             this .resolvedDataSources.put(lookupKey, dataSource);
         }
         if  ( this .defaultTargetDataSource !=  null ) {
             this .resolvedDefaultDataSource = resolveSpecifiedDataSource( this .defaultTargetDataSource);
         }
     }
}

1.AbstractRoutingDataSource中的成员变量,和初始化所做的事情(转换并保存Map<key, DataSource>,可设置key不存在时候的默认DataSourcere)

 

      AbstractRoutingDataSource中有targetDataSources,AbstractRoutingDataSource初始化会依赖注入配置文件中你所配置的DataSource, 并保存于Map中(结构为key-DataSource,其中key为配置文件中设置的,key是为了标识对应的数据库,后续动态获取时会从ThreadLocal中获取key),最终你所需要的数据库连接是通过你给于的key去获取,覆写determineCurrentLookupK

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值