mysql主从同步springboot_SpringBoot AOP Mysql主从复制

本文介绍了如何在SpringBoot应用中利用AOP和AbstractRoutingDataSource进行MySQL主从数据源的切换。详细步骤包括配置主从数据源、定义HandleDataSource类管理数据源、创建自定义路由数据源实现类、配置数据源路由、定义注解选择数据源以及通过AOP在方法执行前动态切换数据源。
摘要由CSDN通过智能技术生成

SpringBoot AOP Mysql主从复制

1.原理

借助spring的【org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource】这个抽象类实现,来进行·数据源的路由,并通过Aop 进行路由选择。

2 配置主从数据源

###datasource

spring.datasource.master.driverClassName = com.mysql.jdbc.Driver

#多数据源时,为master

spring.datasource.master.url = jdbc:mysql://192.168.18.131:3339/usermanage

spring.datasource.master.username = root

spring.datasource.master.password = 123456

spring.datasource.slave.driverClassName= com.mysql.jdbc.Driver

多数据源时,为slave

spring.datasource.slave.url = jdbc:mysql://192.168.18.131:3340/usermanage

spring.datasource.slave.username =root

spring.datasource.slave.password =123456

3定义HandleDataSource类来获取当前线程的数据源类型

/**

* Created by huanghengbo on 2019/8/21.

*/

public class HandleDataSource {

public static final ThreadLocal holder = new ThreadLocal();

/**

* 绑定当前线程数据源

*

* @param key

*/

public static void putDataSource(String datasource)

{

holder.set(datasource);

}

/**

* 获取当前线程的数据源

*

* @return

*/

public static String getDataSource()

{

return holder.get();

}

}

4定义路由数据源的实现类MyAbstractRoutingDataSource

/**

* Created by huanghengbo on 2019/8/20.

*/

public class MyAbstractRoutingDataSource extends AbstractRoutingDataSource{

private final Logger log = LoggerFactory.getLogger(this.getClass());

@Override

protected Object determineCurrentLookupKey() {

log.info(HandleDataSource.getDataSource());

return HandleDataSource.getDataSource();//获取对应的数据源

}

}

5新建配置类配置数据源数据源和路由配置

@Configuration

public class DataSourceConfig {

//主数据源

@Bean()

@ConfigurationProperties(prefix = "spring.datasource.master")

public DataSource MasterDataSource() {

return DataSourceBuilder.create().build();

}

//从数据源

@Bean()

@ConfigurationProperties(prefix = "spring.datasource.slave")

public DataSource SlaveDataSource() {

return DataSourceBuilder.create().build();

}

/**

* 设置数据源路由,通过该类中的determineCurrentLookupKey决定使用哪个数据源

*/

@Bean

public AbstractRoutingDataSource routingDataSource() {

MyAbstractRoutingDataSource proxy = new MyAbstractRoutingDataSource();

Map targetDataSources = new HashMap<>(2);//存放对于数据源的映射

targetDataSources.put("master", MasterDataSource());

targetDataSources.put("slave", SlaveDataSource());

proxy.setDefaultTargetDataSource(MasterDataSource());

proxy.setTargetDataSources(targetDataSources);

return proxy;

}

@Bean(name = "SqlSessionFactory")

@Primary

public SqlSessionFactory MasterSqlSessionFactory( DataSource routingDataSource) throws Exception {

SqlSessionFactoryBean bean = new SqlSessionFactoryBean();

bean.setDataSource(routingDataSource);//DataSource使用路由数据源

//���XMLĿ¼

ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

try {

bean.setMapperLocations(resolver.getResources("classpath*:mappers/*.xml"));

bean.setConfigLocation(resolver.getResource("classpath:mybatis-config.xml"));

return bean.getObject();

} catch (Exception e) {

e.printStackTrace();

throw new RuntimeException(e);

}

}

@Bean(name = "TransactionManager")

@Primary

public DataSourceTransactionManager testTransactionManager(DataSource routingDataSource) {

return new DataSourceTransactionManager(routingDataSource);

}

@Bean(name = "SqlSessionTemplate")

@Primary

public SqlSessionTemplate MasterSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception {

return new SqlSessionTemplate(sqlSessionFactory);

}

}

6新建DataSource注解来注释Mapper接口所要使用的数据源

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface DataSource

{

String value();//设置数据源类型

}

7配置Aop

@Aspect

@Component

public class DataSourceAspect {

/**

* 在dao层方法获取datasource对象之前,在切面中指定当前线程数据源

*/

@Pointcut("execution(* com.spring.dao*..*(..))")//切点为所有的mapper接口

public void pointcut(){

}

@Before("pointcut()")

public void before(JoinPoint point)

{

System.out.println("before");

Object target = point.getTarget();

String method = point.getSignature().getName();

Class>[] classz = target.getClass().getInterfaces(); // 获取目标类的接口, 所以@DataSource需要写在接口上

Class>[] parameterTypes = ((MethodSignature) point.getSignature())

.getMethod().getParameterTypes();

try

{

Method m = classz[0].getMethod(method, parameterTypes);

if (m != null && m.isAnnotationPresent(DataSource.class))

{

DataSource data = m.getAnnotation(DataSource.class);

System.out.println("用户选择数据库库类型:" + data.value());

HandleDataSource.putDataSource(data.value()); // 数据源放到当前线程中

}

} catch (Exception e)

{

e.printStackTrace();

}

}

}

10 在对应的mapper方法上使用注解DataSource("")来设置数据源类型

@DataSource("slave")

List selectByExample(TbUserExample example);

11 测试结果

6cfaba16281ffb45c75c798851458bdd.png总结:通过AOP来确定所使用数据源类型,然后通过路由来进行数据源选择。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值