# multi-datasource **Repository Path**: fancie/multi-datasource ## Basic Information - **Project Name**: multi-datasource - **Description**: Springboot+JPA实现读写分离(动态切换数据源) - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 1 - **Created**: 2022-02-08 - **Last Updated**: 2023-08-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: SpringBoot, JPA ## README # Springboot+JPA实现读写分离 方案 ---- 利用AbstractRoutingDataSource动态切换到主库或者从库 原理 ------- 1.添加注解 ``` @TargetDataSource(value = DataSourceNames.slave) ``` 2.切换相应的数据(此时只配置了一个名称) 以下代码就做一件事情:给RoutingDataSource的CONTEXT_HOLDER赋值。 ``` @Around("@annotation(targetDataSource)") public Object routingWithDataSource(ProceedingJoinPoint joinPoint, TargetDataSource targetDataSource) throws Throwable { if (targetDataSource == null) { RoutingDataSource.setDataSource(DataSourceNames.master); } else { RoutingDataSource.setDataSource(targetDataSource.value()); } try { return joinPoint.proceed(); } finally { RoutingDataSource.clearDataSource(); } } ``` 3.选择数据库(通过第二步的名称) AbstractRoutingDataSource会根据RoutingDataSource的CONTEXT_HOLDER赋值选择数据库 ``` 这里是AbstractRoutingDataSource的代码,RoutingDataSource重写了this.determineCurrentLookupKey()方法。 protected DataSource determineTargetDataSource() { Assert.notNull(this.resolvedDataSources, "DataSource router not initialized"); Object lookupKey = this.determineCurrentLookupKey(); DataSource dataSource = (DataSource)this.resolvedDataSources.get(lookupKey); if (dataSource == null && (this.lenientFallback || lookupKey == null)) { dataSource = this.resolvedDefaultDataSource; } if (dataSource == null) { throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]"); } else { return dataSource; } } ``` JPA在执行sql之前都会调用determineTargetDataSource方法,这就实现的动态的切换数据库。 ---------- fancie 杭州