多数据源下配置shardingjdbc,导致主数据源失效的场景
配置主数据源和通过shardingjdbc进行分表配置
本人在此次分表过程中遇到了这样的事情,主业务都在主数据源上,分表的数据源和主数据源不是同一个数据库。一切配置好后,分表插入数据也没有问题,后面测试主业务场景时,发现主数据源失效,楞是花了我大半天时间才找到原因,在这里分享下,希望你们不会遇到。
先看主要配置信息
- 引入需要的依赖
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
<!--依赖dynamic-datasource-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-core-common</artifactId>
<version>4.0.0-RC1</version>
</dependency>
- 进行数据源配置
spring:
application:
# 应用名称
name: weygy
profiles:
# 环境配置
active: dev
main:
allow-bean-definition-overriding: true
datasource:
dynamic:
primary: master
datasource:
master:
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/center?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowMultiQueries=true
driver-class-name: com.mysql.cj.jdbc.Driver
shardingsphere:
datasource:
names: logging
logging:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/report?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowMultiQueries=true
username: root
password: root
type: com.zaxxer.hikari.HikariDataSource
sharding:
#指定data表的数据分布情况。
#data_$->{1..3}:logging.data_1;logging.data_2;
tables:
data:
actual-data-nodes: logging.data_$->{1..3}
#指定表的主键生成策略SNOWFLAKE
key-generator:
column: data_id
type: SNOWFLAKE
#指定表的分片策略,包括分片键和分片算法
table-strategy:
inline:
sharding-column: data_id
algorithm-expression: data_$->{data_id % 3 + 1}
这里分了三张表
- 添加Dynamic-datasource的动态数据源配置类
package cn.logging.config;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Map;
/**
* @ClassName: DataSourceConfiguration
* @Description: Dynamic-datasource的动态数据源配置类
* @author: Sir
* @date: 2023/4/18 17:55
* @version: 1.0
**/
@Configuration
@AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class, SpringBootConfiguration.class})
public class DataSourceConfiguration {
@Resource
private DynamicDataSourceProperties properties;
/**
* shardingjdbc有四种数据源,需要根据业务注入不同的数据源
*
* <p>1. 未使用分片, 脱敏的名称(默认): shardingDataSource;
* <p>2. 主从数据源: masterSlaveDataSource;
* <p>3. 脱敏数据源:encryptDataSource;
* <p>4. 影子数据源:shadowDataSource
* <p>5. 分片使用数据源:shardingSphereDataSource
*
*/
@Lazy
@Resource
private DataSource shardingSphereDataSource;
@Bean
public DynamicDataSourceProvider dynamicDataSourceProvider() {
Map<String, DataSourceProperty> datasourceMap = properties.getDatasource();
return new AbstractDataSourceProvider() {
@Override
public Map<String, DataSource> loadDataSources() {
Map<String, DataSource> dataSourceMap = createDataSourceMap(datasourceMap);
dataSourceMap.put("sharding", shardingSphereDataSource);
//打开下面的代码可以把 shardingjdbc 管理的数据源也交给动态数据源管理 (根据自己需要选择开启)
//dataSourceMap.putAll(((MasterSlaveDataSource) masterSlaveDataSource).getDataSourceMap());
return dataSourceMap;
}
};
}
/**
* 将动态数据源设置为首选的
* 当spring存在多个数据源时, 自动注入的是首选的对象
* 设置为主要的数据源之后,就可以支持shardingjdbc原生的配置方式了
*/
@Primary
@Bean
public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
dataSource.setPrimary(properties.getPrimary());
dataSource.setStrict(properties.getStrict());
dataSource.setStrategy(properties.getStrategy());
dataSource.setProvider(dynamicDataSourceProvider);
dataSource.setP6spy(properties.getP6spy());
dataSource.setSeata(properties.getSeata());
return dataSource;
}
}
- 场景测试
分表的插入数据场景,需要加上:@DS(“sharding”)
@Override
@DS("sharding")
public ResultDataVo reportEvent() {
ReportData data = new ReportData();
loggingService.reportEvent(data);
return getVo(dto);
}
主业务插入数据场景:不用加注解,默认进入
@Service
public class loggingEventServiceImpl implements loggingEventService {
@Autowired
private loggingEventMapper loggingEventMapper;
@Override
public void insertloggingEvent(loggingEventPo loggingEventPo) {
loggingEventMapper.insertloggingEvent(loggingEventPo);
}
}
出现问题的场景
### Cause: java.sql.SQLSyntaxErrorException: Table 'logging_report.event' doesn't exist
这里出现该问题的主要原因可以在:Dynamic-datasource的动态数据源配置类中查看出来,这里只进入了第一个断点,没有进入第二个断点
问题修改
修改方法将依赖版本增加到4.1
此时进入第二个断点,加载数据源。主数据源使用不需要加注解,默认主数据源,分表的数据源使用需要加注解:@DS(“sharding”)
后续又遇到了其它场景