springboot+mybatis的多数据源配置
1.链接数据库yml配置
spring:
datasource:
master:
jdbc-url: jdbc:mysql://localhost:3306/dams?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
slave1:
jdbc-url: jdbc:mysql://localhost:3306/root?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
slave2:
jdbc-url: jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
2.数据源配置
/**
* * 关于数据源配置,参考SpringBoot官方文档第79章《Data Access》 * 79. Data Access
* * 79.1 Configure a Custom DataSource * 79.2 Configure Two DataSources
*/
@Configuration
public class DataSourceConfig {
//将master数据源注入
@Bean
@Primary
@ConfigurationProperties("spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
//将slave1注入
@Bean
@ConfigurationProperties("spring.datasource.slave1")
public DataSource slave1DataSource() {
return DataSourceBuilder.create().build();
}
//将slave2注入
@Bean
@ConfigurationProperties("spring.datasource.slave2")
public DataSource slave2DataSource() {
return DataSourceBuilder.create().build();
}
// 我们配置了4个数据源,1个master,2两个slave,1个路由数据源。前3个数据源都是为了生成第4个数据源,而且后续我们只用这最后一个路由数据源。
@Bean
public DataSource myRoutingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
@Qualifier("slave1DataSource") DataSource slave1DataSource,
@Qualifier("slave2DataSource") DataSource slave2DataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DBTypeEnum.MASTER, masterDataSource);
targetDataSources.put(DBTypeEnum.SLAVE1, slave1DataSource);
targetDataSources.put(DBTypeEnum.SLAVE2, slave2DataSource);
MyRoutingDataSource myRoutingDataSource = new MyRoutingDataSource();
myRoutingDataSource.setDefaultTargetDataSource(masterDataSource);// 主库数据源
myRoutingDataSource.setTargetDataSources(targetDataSources);// 路由数据源
return myRoutingDataSource;
}
}
3.SqlSessionFactory
@EnableTransactionManagement
@Configuration
public class MyBatisConfig {
@Resource(name = "myRoutingDataSource")
private DataSource myRoutingDataSource;
//将数据源设置到SqlSessionFactory
@Bean
public SqlSessionFactory sqlSessionFactory( MybatisProperties mybatisProperties) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(myRoutingDataSource);
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
sqlSessionFactoryBean.setConfiguration(mybatisProperties.getConfiguration());
return sqlSessionFactoryBean.getObject();
}
//将数据源设置到事务平台管理器
@Bean
public PlatformTransactionManager platformTransactionManager() {
return new DataSourceTransactionManager(myRoutingDataSource);
}
}
4.
public enum DBTypeEnum {
MASTER,SLAVE1,SLAVE2;
}
//定义注解用来强制访问主库
public @interface Master {
}
//数据库切换
public class DBContextHolder {
//定义变量副本
private static final ThreadLocal<DBTypeEnum> contextHolder = new ThreadLocal<>();
//定义安全自增
private static final AtomicInteger counter = new AtomicInteger(-1);
public static void set(DBTypeEnum dbType) {
contextHolder.set(dbType);
}
public static DBTypeEnum get() {
return contextHolder.get();
}
public static void master() {
set(DBTypeEnum.MASTER);
System.out.println("切换到master");
}
public static void slave() {
// 轮询切换从数据库
int index = counter.getAndIncrement() % 2;
if (counter.get() > 9999) {
counter.set(-1);
}
if (index == 0) {
set(DBTypeEnum.SLAVE1);
System.out.println("切换到slave1");
}else {
set(DBTypeEnum.SLAVE2);
System.out.println("切换到slave2");
}
}
}
5.
public class MyRoutingDataSource extends AbstractRoutingDataSource {
//根据路由来确定map中的sqlsessionFactory
@Nullable
@Override
protected Object determineCurrentLookupKey() {
return DBContextHolder.get();
}
}
6.注入多数据源
public class DataSourceAop {
@Pointcut("!@annotation(com.tl.base.datasource.annotation.Master) " +
"&& (execution(* com.tl.base.domain..*.query*(..)) " +
"|| execution(* com.tl.base.domain..*.get*(..)))")
public void readPointcut() {
}
@Pointcut("@annotation(com.tl.base.datasource.annotation.Master) " +
"|| execution(* com.tl.base.domain..*.insert*(..)) " +
"|| execution(* com.tl.base.domain..*.add*(..)) " +
"|| execution(* com.tl.base.domain..*.update*(..)) " +
"|| execution(* com.tl.base.domain..*.edit*(..)) " +
"|| execution(* com.tl.base.domain..*.delete*(..)) " +
"|| execution(* com.tl.base.domain..*.remove*(..))")
public void writePointcut() {
}
@Before("readPointcut()")
public void read() {
DBContextHolder.slave();
}
@Before("writePointcut()")
public void write() {
DBContextHolder.master();
}
如果你不知道自己要去哪里,那么去哪里都是一样

浙公网安备 33010602011771号