最近遇到一个报错:
The MySQL server is running with the --read-only option so it cannot execute this statement
查询报错原因是因为更新操作连接到了数据库的读库造成的。为什么会连到读库呢?追踪代码发现利用了动态数据源
@Service
@DS("abc")
public class XXXServiceImpl extends ServiceImpl<XXXMapper, XXX> implements XXXService {
}
去看数据库配置发现配置为
datasource:
dynamic:
primary: master
strict: false
datasource:
master:
---- 数据库配置
abc_read:
---- 数据库配置
这里@DS 配置的是abc,但是数据源里面配置的是abc_read,默认应该是选择master库,但是查看日志却是使用的abc_read。是不是DynamicDataSource 有特殊处理呢。追踪源码,找到DynamicRoutingDataSource类
private DataSource determinePrimaryDataSource() {
log.debug("dynamic-datasource switch to the primary datasource");
DataSource dataSource = dataSourceMap.get(primary);
if (dataSource != null) {
return dataSource;
}
GroupDataSource groupDataSource = groupDataSources.get(primary);
if (groupDataSource != null) {
return groupDataSource.determineDataSource();
}
throw new CannotFindDataSourceException("dynamic-datasource can not find primary datasource");
}
发现
/**
* 分组数据库
*/
private final Map<String, GroupDataSource> groupDataSources = new ConcurrentHashMap<>();
中有key是abc,找到初始化这个map的代码
/**
* 新数据源添加到分组
*
* @param ds 新数据源的名字
* @param dataSource 新数据源
*/
private void addGroupDataSource(String ds, DataSource dataSource) {
if (ds.contains(UNDERLINE)) {
String group = ds.split(UNDERLINE)[0];
GroupDataSource groupDataSource = groupDataSources.get(group);
if (groupDataSource == null) {
try {
groupDataSource = new GroupDataSource(group, strategy.getDeclaredConstructor().newInstance());
groupDataSources.put(group, groupDataSource);
} catch (Exception e) {
throw new RuntimeException("dynamic-datasource - add the datasource named " + ds + " error", e);
}
}
groupDataSource.addDatasource(ds, dataSource);
}
}
private static final String UNDERLINE = "_";
这个逻辑就是数据源中有“_”时,DynamicDataSource会将下划线切分后的第一个词作为key,如果@ds 里面有这个值,就默认会用这个数据源了。所以如果不需要用到数据源分组功能的时候,在配置数据源的时候不要用“_”,否则数据源会切到不确定的数据源。
这个分组功能应该是集群情况下,对多个库做loadbalance用的。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。