读写分离:写走主库,读走从库
分库分表:通常有两种路由算法,范围或hash。
1.实现动态数据源
spring提供了抽象类AbstractRoutingDataSource,里面有两个重要的参数,
targetDataSources代表提供的数据源。
defaultTargetDataSource代表默认数据源。
public void setTargetDataSources(Map还有一个抽象方法
@Nullable
protected abstract Object determineCurrentLookupKey();我们可以继承AbstractRoutingDataSource,实现determineCurrentLookupKey方法进行动态路由数据源。实现如下:
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
private static ThreadLocal ROUTING_KEY = new ThreadLocal<>();
@Override
protected Object determineCurrentLookupKey() {
return ROUTING_KEY.get();
}
public static void setRoutingKey(String routingKey) {
ROUTING_KEY.set(routingKey);
}
public static void removeRoutingKey() {
ROUTING_KEY.remove();
}
//不用重写改方法,这里是为了打印数据源信息
@Override
public Connection getConnection() throws SQLException {
DataSource dataSource = this.determineTargetDataSource();
logger.info(dataSource);
return dataSource.getConnection();
}
} 2.基于注解的方式,实现动态切换数据源
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Master {
}@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Slave {
}
@Aspect
@Component
@Order(-99)
public class MasterAop {
@Pointcut("@annotation(com.example.demo.aop.Master)")
public void recordAspect() {}
@Around("recordAspect()")
public Object recordAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
try {
DynamicRoutingDataSource.setRoutingKey("master");
return proceedingJoinPoint.proceed();
} finally {
DynamicRoutingDataSource.removeRoutingKey();
}
}
}@Aspect
@Component
@Order(-99)
public class SlaveAop {
@Pointcut("@annotation(com.example.demo.aop.Slave)")
public void recordAspect() {
}
@Around("recordAspect()")
public Object recordAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
try {
DynamicRoutingDataSource.setRoutingKey("slave");
return proceedingJoinPoint.proceed();
} finally {
DynamicRoutingDataSource.removeRoutingKey();
}
}
}3.配置数据源
@Bean
@Primary
public DataSource dataSource() {
DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
HikariConfig masterHikariConfig = new HikariConfig();
masterHikariConfig.setPassword("xx");
masterHikariConfig.setUsername("xx");
masterHikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
masterHikariConfig.setJdbcUrl("jdbc:mysql://xxxx?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true");
masterHikariConfig.setPoolName("masterPool");
HikariDataSource masterDataSource = new HikariDataSource(masterHikariConfig);
HikariConfig slaveHikariConfig = new HikariConfig();
slaveHikariConfig.setPassword("xx");
slaveHikariConfig.setUsername("xx");
slaveHikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
slaveHikariConfig.setJdbcUrl("jdbc:mysql://xxxx?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true");
slaveHikariConfig.setPoolName("slavePool");
HikariDataSource slaveDataSource = new HikariDataSource(slaveHikariConfig);
HashMap4.实现一个测试Service
@Service
@Slf4j
public class MasterSlaveService {
@Slave
@Transactional
public void slaveTest() {
}
@Master
@Transactional
public void masterTest() {
}
}5.测试如下
@SpringBootApplication
@EnableTransactionManagement
public class RoutingDataSourceDemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(RoutingDataSourceDemoApplication.class, args);
MasterSlaveService bean = run.getBean(MasterSlaveService.class);
bean.masterTest();
bean.slaveTest();
}
}
我们可以看到数据源的切换信息
com.zaxxer.hikari.HikariDataSource : masterPool - Starting...
com.zaxxer.hikari.HikariDataSource : masterPool - Start completed.
com.zaxxer.hikari.HikariDataSource : slavePool - Starting...
com.zaxxer.hikari.HikariDataSource : slavePool - Start completed.
c.e.d.RoutingDataSourceDemoApplication : Started RoutingDataSourceDemoApplication in 2.054 seconds (JVM running for 2.682)
c.e.d.d.DynamicRoutingDataSource : HikariDataSource (masterPool)
c.e.d.d.DynamicRoutingDataSource : HikariDataSource (slavePool)如果业务简单,我们可以自己实现数据源的切换,如果复杂的话,建议使用ShardingSphere框架,ShardingSphere是基于更底层的jdbc代理实现。
| 留言与评论(共有 0 条评论) “” |