mysql主从设置参考:mysql主从设置
1. pom设置
spring:
data:
master:
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://192.168.1.47:3306/im-block?autoReconnect=true&useUnicode=true&allowMultiQueries=true&characterEncoding=utf-8&useSSL=false
username: root
password: 1204
slave:
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://192.168.1.49:3306/im-block?autoReconnect=true&useUnicode=true&allowMultiQueries=true&characterEncoding=utf-8&useSSL=false
username: imblock
password: 1204
2. 定义主从类型:
public enum DBTypeEnum {
MASTER,
SLAVE;
}
3. 定义路由数据源的实现类
public class DbDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
System.out.println("DBContextHolder.getDb()=="+DBContextHolder.getDb());
return DBContextHolder.getDb();
}
}
4. 定义线程切换
public class DBContextHolder {
private static final ThreadLocal<DBTypeEnum> contextHolder = new ThreadLocal<>();
public static void setDb(DBTypeEnum dbType) {
contextHolder.set(dbType);
}
public static DBTypeEnum getDb() {
return contextHolder.get();
}
public static void remove() {
System.out.println("移除线程="+contextHolder.get());
System.out.println("移除线程");
contextHolder.remove();
}
}
5. 配置数据源数据源和路由配置
@Configuration
public class DbConfig {
@Bean
@Primary
@ConfigurationProperties("spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public DataSource sqlDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
@Qualifier("slaveDataSource") DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DBTypeEnum.MASTER, masterDataSource);
targetDataSources.put(DBTypeEnum.SLAVE, slaveDataSource);
DbDataSource dbDataSource = new DbDataSource();
dbDataSource.setDefaultTargetDataSource(masterDataSource);
dbDataSource.setTargetDataSources(targetDataSources);
return dbDataSource;
}
}
@Configuration
@EnableTransactionManagement
public class SqlConfig {
@Resource(name = "sqlDataSource")
private DataSource sqlDataSource;
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setDataSource(sqlDataSource);
sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:mapper/*/*.xml"));
Objects.requireNonNull(sqlSessionFactoryBean.getObject()).getConfiguration().setMapUnderscoreToCamelCase(true);
return sqlSessionFactoryBean.getObject();
}
@Bean
public PlatformTransactionManager platformTransactionManager() {
return new DataSourceTransactionManager(sqlDataSource);
}
}
6.设置切面与注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DataSource {
DBTypeEnum value() default DBTypeEnum.MASTER;
}
@Aspect
@Component
@Service
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DataSourceAspect {
protected Logger logger = LoggerFactory.getLogger(getClass());
@Pointcut("@annotation(com.imblock.common.annotation.DataSource) " +
"|| @within(com.imblock.common.annotation.DataSource)")
public void dataSourcePointCut() {
logger.debug("dataSourcePointCut in");
}
@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Class targetClass = point.getTarget().getClass();
Method method = signature.getMethod();
DataSource targetDataSource = (DataSource)targetClass.getAnnotation(DataSource.class);
DataSource methodDataSource = method.getAnnotation(DataSource.class);
if(targetDataSource != null || methodDataSource != null){
DBTypeEnum value;
if(methodDataSource != null){
value = methodDataSource.value();
}else {
value = targetDataSource.value();
}
DBContextHolder.setDb(value);
logger.debug("set datasource is {}", value);
}
try {
return point.proceed();
} finally {
DBContextHolder.remove();
logger.debug("clean datasource");
}
}
7. 在需要切换的方法上加
@DataSource(DBTypeEnum.SLAVE)
FAQ:注意点:
注解在controller是有效的,但是如果引入了shiro,在service层是无效的,需要在认证的类里面将注入的service类全部延迟启动。不然是无效的。