spring多数据源实现读写分离

一、常用场景

读写分离:写走主库,读走从库

分库分表:通常有两种路由算法,范围或hash。

二、读写分离实现方法

1.实现动态数据源

spring提供了抽象类AbstractRoutingDataSource,里面有两个重要的参数,

targetDataSources代表提供的数据源。

defaultTargetDataSource代表默认数据源。

public void setTargetDataSources(Map targetDataSources) { this.targetDataSources = targetDataSources;}public void setDefaultTargetDataSource(Object defaultTargetDataSource) { this.defaultTargetDataSource = defaultTargetDataSource;}

还有一个抽象方法

@Nullableprotected 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)@Documentedpublic @interface Master {}@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @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@Primarypublic 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); HashMap targetDataSources = new HashMap(); targetDataSources.put(“master”, masterDataSource); targetDataSources.put(“slave”, slaveDataSource); dynamicRoutingDataSource.setTargetDataSources(targetDataSources); return dynamicRoutingDataSource;}

4.实现一个测试Service

@Service@Slf4jpublic class MasterSlaveService { @Slave @Transactional public void slaveTest() { } @Master @Transactional public void masterTest() { }}

5.测试如下

@SpringBootApplication@EnableTransactionManagementpublic 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代理实现。

郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
(0)
用户投稿
上一篇 2022年7月1日
下一篇 2022年7月1日

相关推荐

联系我们

联系邮箱:admin#wlmqw.com
工作时间:周一至周五,10:30-18:30,节假日休息