Spring+Mybatis配置主从数据库

1、数据库的主从分离原理

  现在大型的网站服务,在数据库层面大多采用读写分离技术,就是一个数据库负责数据的创建、更新和删除以及实时查询,这个数据库成为主数据库;另外的数据库主要负责非实时数据的查询,称为从数据库。因为在实际的应用中,数据库都是读多写少(读取数据的频率高,更新数据的频率相对较少),而读取数据通常耗时比较长,占用数据库服务器的CPU较多,影响用户体验。把查询从主库中抽取出来,采用多个从库,使用负载均衡,可以减轻每个从库的查询压力。

2、数据库主从分离的实现

  在开发中,怎么实现数据库主从的读写分离呢?常见的方式有:定义2个数据库连接,一个是MasterDataSource,另一个是SlaveDataSource。更新数据时读取MasterDataSource,查询数据时读取SlaveDataSource。那么,问题来了,以往在spring和hibernate或者Mybatis框架中总是配置一个数据源,因而sessionFactory的dataSource属性总是指向这个数据源并且恒定不变,所有DAO在使用sessionFactory的时候都是通过这个数据源访问数据库。但是现在怎样很方便的切换多个数据源呢?

    文章如何在spring框架中解决多数据源的问题 给出了一个比较好的解决方案。

   1)掌握配置的前提知识

    Spring对数据库的连接进行了封装,使得在利用spring配置数据源的时候,可以很方便的进行。

    spring 的AbstractRoutingDataSource 类。

public abstract AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
    private Map targetDataSources;  
  
    private Object defaultTargetDataSource;  
  
    private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();  
  
    private Map resolvedDataSources;  
  
    private DataSource resolvedDefaultDataSource;  
}

  2)所以核心思想就是在选择数据库链接的时候,先选择出数据源。可以对AbstractRoutingDataSource进行扩展,在determineCurrentLookupKey中选择合适的数据源。结合思想有:

public class DynamicDataSource extends AbstractRoutingDataSource {  
  @Override    
  protected Object determineCurrentLookupKey() {       
     return DataSourceContextHolder.getType();    
    }
}

 DataSourceContextHolder由线程绑定,

public class DataSourceContextHolder {
    
    public static final String DATA_SOURCE_1 = "ds1";
    public static final String DATA_SOURCE_2 = "ds2";
    
    private static final ThreadLocal contextHolder = new ThreadLocal();

    // 设置数据源类型
    public static void setType(String type) {
        contextHolder.set(type);
    }
    // 获取数据源类型
    public static String getType() {
        return (contextHolder.get());
    }
    // 清除数据源类型
    public static void clearType() {
        contextHolder.remove();
    }
}

什么时候设置线程绑定变量呢?可以u借助AOP,在执行方法之前设置好holder。

@Component
@Aspect
public class DynamicDataSourceAspect {

    @Pointcut("execution (* com.chen.test.mapper.ds1.*.*(..))")
    public void dsMethodPointcut() {}

    @Pointcut("execution (* com.chen.test.mapper.ds2.*.*(..))")
    public void rdsMethodPointcut() {}

    @Before("dsMethodPointcut()")
    public void switchReadDataSource(){
        DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_DS1);
    }

    @Before("rdsMethodPointcut()")
    public void switchWriteDataSource(){
       DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_DS2);
    }

}

但是,数据源i涉及到事务问题,所以需要在选择数据源之后,事务才被生效。可以通过aop的顺序实现这个。

在Aspect设置顺序为transaction order -1;

 

你可能感兴趣的:(Spring学习)