springboot 2.1.4多数据源配置
-
- 第一步配置数据库连接
- 第二步配置sqlSessionFactory
- 第三步动态实现数据切换
第一步配置数据库连接
首先配置在application.properties问件配置数据库连接,当前springboo版本默认集成了hikari连接池,所以不用在pom里面引入依赖。
第二步配置sqlSessionFactory
@Configuration
@MapperScan(basePackages = "com.ppzdz.datasource.mapper", sqlSessionFactoryRef = "SqlSessionFactory")
public class DataSourceConfig {
@Primary
@Bean(name = "masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource getDateSource1() {
HikariDataSource build = (HikariDataSource) DataSourceBuilder.create().build();
build.setMaximumPoolSize(100);
build.setConnectionTimeout(5000);
return build;
}
@Bean(name = "slave1DataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave1")
public DataSource getDateSource2() {
HikariDataSource build = (HikariDataSource)DataSourceBuilder.create().build();
build.setConnectionTimeout(5000);
build.setIdleTimeout(5000);
return build;
}
@Bean(name = "slave2DataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave2")
public DataSource getDateSource3() {
HikariDataSource build = (HikariDataSource)DataSourceBuilder.create().build();
build.setConnectionTimeout(5000);
build.setIdleTimeout(5000);
return build;
}
@Bean(name = "dynamicDataSource")
public DynamicDataSource DataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
@Qualifier("slave1DataSource") DataSource slave1DataSource,
@Qualifier("slave2DataSource") DataSource slave2DataSource) {
Map<Object, Object> targetDataSource = new HashMap<>();
targetDataSource.put(DataSourceType.DataBaseType.MASTER, masterDataSource);
targetDataSource.put(DataSourceType.DataBaseType.SLAVE1, slave1DataSource);
targetDataSource.put(DataSourceType.DataBaseType.SLAVE2, slave2DataSource);
DynamicDataSource dataSource = new DynamicDataSource();
dataSource.setTargetDataSources(targetDataSource);
dataSource.setDefaultTargetDataSource(masterDataSource);
return dataSource;
}
@Bean(name = "SqlSessionFactory")
public SqlSessionFactory masterSqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dynamicDataSource);
bean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml"));
return bean.getObject();
}
}
- @Configuration用于定义配置类,可替换xml配置文件
- @MapperScan扫描mybatis的mapper(dao)层的接口
- @Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
- @Primary可以理解为默认优先选择,上面为默认数据源的配置
- @ConfigurationProperties它可以把同类的配置信息自动封装成实体类,这里就是application.properties里的数据库连接自动封装
dataSource.setDefaultTargetDataSource(masterDataSource);默认数据源。不要忘了
是不是DynamicDataSource 有问题??,好像没有这个包??哈哈
第三步动态实现数据切换
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
DataSourceType.DataBaseType dataBaseType = DataSourceType.getDataBaseType();
return dataBaseType;
}
}
DynamicDataSource 这个类是自己定义的,重写了determineCurrentLookupKey()方法,AbstractRoutingDataSource
- 多数据源的动态切换,在程序运行时,把数据源数据源动态织入到程序中,灵活的进行数据源切换。
- 基于多数据源的动态切换,我们可以实现读写分离,这么做缺点也很明显,无法动态的增加数据源。
总之这个呢是切换数据源用的,详细信息大家可以看下源码。
编写AbstractRoutingDataSource的实现类,DataSourceType 就是提供给我们动态选择数据源的数据的信息,这里编写一个根据当前线程来选择数据源,然后通过AOP拦截特定的注解,设置当前的数据源信息。
public class DataSourceType {
public enum DataBaseType {
MASTER ,SLAVE1,SLAVE2
}
// 使用ThreadLocal保证线程安全
private static final ThreadLocal<DataBaseType> TYPE = new ThreadLocal<DataBaseType>();
// 往当前线程里设置数据源类型
public static void setDataBaseType(DataBaseType dataBaseType) {
if (dataBaseType == null) {
throw new NullPointerException();
}
System.err.println("[将当前数据源改为]:" + dataBaseType);
TYPE.set(dataBaseType);
}
// 获取数据源类型
public static DataBaseType getDataBaseType() {
DataBaseType dataBaseType = TYPE.get() == null ? DataBaseType.MASTER : TYPE.get();
System.err.println("[获取当前数据源的类型为]:" + dataBaseType);
return dataBaseType;
}
// 清空数据类型
public static void clearDataBaseType() {
TYPE.remove();
}
}
最后一步
- 基于aop动态切换
@Aspect
@Component
public class DataSourceAop {
@Before("execution(* com.ppzdz.datasource.service..*.master*(..))")
public void setDataSource3Master() {
System.err.println("Master业务");
DataSourceType.setDataBaseType(DataBaseType.MASTER);
}
@Before("execution(* com.ppzdz.datasource.service..*.slave1*(..))")
public void setDataSource3Slave1() {
System.err.println("Slave1业务");
DataSourceType.setDataBaseType(DataBaseType.SLAVE1);
}
@Before("execution(* com.ppzdz.datasource.service..*.slave2*(..))")
public void setDataSource3Slave2() {
System.err.println("Slave2业务");
DataSourceType.setDataBaseType(DataBaseType.SLAVE2);
}
}
注意这是监听业务层的方法调用,在调用前注入数据源,方法名是否含有slave2、slave1。。。。如果都没有默认注入默认数据源。
然后,大功告成。如还有问题,发送邮件到[email protected]。