ShardingJdbc兼容达梦
本章详细说ShardingJdbc和达梦数据库的扩展和配置问题,ShardingJdbc和DruidDataSource、Mybatis整合的兼容、冲突问题,以及这些问题的解决方案。,干货满满,全网独一份,建议收藏。本章不说ShardingJdbc的用法和配置,这些已经烂大街了,有需要的小伙伴自行找资料,一搜一大堆。
原创文章,转载请注明出处,侵权必究。
ShardingJdbc版本扩展数据库类型问题
原因分析
ShardingJdbc默认不兼容达梦,在 sharding-jdbc-spring-boot-starter:4.0.0-RC1
以及更低版本中不支持扩展兼容的数据库类型,因为在该版本中能支持的数据库类型已经被DataSourceMetaDataFactory
写死了,其他未支持的数据库则会抛出UnsupportedOperationException
但在 sharding-jdbc-spring-boot-starter:4.0.0-RC1
之后更高的版本中,DataSourceMetaDataFactory
类已经不存在,兼容的数据库类型通过SPI机制来配置,官方默认支持的数据库类型在包sahrdingsphere-common
包中配置如下:
解决办法
可以利用该机制扩展数据库元数据和数据库类型,以达到支持达梦数据库,代码如下:
/**
* 扩展达梦数据库类型
*/
public class DMDatabaseType implements BranchDatabaseType {
@Override
public String getName() {
// 返回达梦名称
return "DM";
}
@Override
public Collection<String> getJdbcUrlPrefixAlias() {
return Collections.emptyList();
}
@Override
public DataSourceMetaData getDataSourceMetaData(final String url, final String username) {
return new DMDataSourceMetaData(url, username);
}
@Override
public DatabaseType getTrunkDatabaseType() {
return DatabaseTypes.getActualDatabaseType("Oracle");
}
}
/**
* 扩展达梦数据库元数据
*/
@Getter
@Slf4j
public class DMDataSourceMetaData implements DataSourceMetaData {
private static final int DEFAULT_PORT = 5236;
private final String hostName;
private final int port;
private final String catalog;
private final String schema;
// private final Pattern pattern = Pattern.compile("jdbc:dm://([\\w\\-.]+):?([0-9]*)", Pattern.CASE_INSENSITIVE);
/**
* 匹配达梦url的正则表达式,以来解析主机、端口、用户名和密码等
*/
private Pattern pattern = Pattern.compile("jdbc:dm://([\\w\\-\\.]+):?([0-9]*)(/?)([\\w\\-]*)", Pattern.CASE_INSENSITIVE);
public DMDataSourceMetaData(final String url, final String username) {
Matcher matcher = pattern.matcher(url);
if (!matcher.find()) {
throw new UnrecognizedDatabaseURLException(url, this.pattern.pattern());
}
hostName = matcher.group(1);
port = Strings.isNullOrEmpty(matcher.group(2)) ? DEFAULT_PORT : Integer.valueOf(matcher.group(2));
// catalog = username;
// schema = username;
catalog = matcher.group(3);
schema = username;
log.info("hostName: " + this.hostName + " port: " + this.port + " url: " + url + " username: " + username + " catalog: " + this.catalog + " schema: " + this.schema);
}
}
以上代码来源:https://blog.csdn.net/wyl614548134/article/details/135980260
ShardingJdbc、DruidDataSource和Mybatis版本兼容问题
原因分析
sharding-jdbc-spring-boot-starter:4.0.0-RC1
以前以及更低版本中,程序启动的时候,ShardingJdbc自动配置类(SpringBootConfiguration
)会创建一个名为dataSource的数据源bean,和druid-spring-boot-starter
的自动配置类(DruidDataSourceAutoConfigure
)产生的数据源bean都为dataSource,名称产生冲突。
所以需要添加配置spring.main.allow-bean-definition-overriding=true
,让ShardingJdbc的dataSource覆盖Druid的dataSource,以解决bean name冲突的问题。
而在sharding-jdbc-spring-boot-starter:4.0.0-RC1
之后以及更高的版本中,ShardingJdbc自动配置类(SpringBootConfiguration
)产生的数据源bean为shardingDataSource,和Druid数据源bean为dataSource不产生冲突,但在IOC容器中会存在shardingDataSource和dataSource两个数据源。
在IOC容器存在两个数据源会导致时,会导致标注有@Mapper
的dao接口注入报错(因为此时并未在IOC容器中生成接口动态代理bean),原因在于mybatis的自动配置类(MybatisAutoConfiguration
)不生效,因为该配置类有一个生效条件是,当IOC容器只有一个标注**@Primary**或者有且只有一个类型为DataSource的bean时才生效。
启动的时候,mybatis的自动配置类(MybatisAutoConfiguration
)匹配情况如下:
解决办法一(推荐):
在spring的配置文件中添加spring.autoconfigure.exclude=com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
,该配置会禁止DruidDataSourceAutoConfigure
自动配置失效,从而保证IOC容器中只有一个DataSource
,从而使Mybatis的自动配置生效,效果如下:
解决办法二(看看就行):
ShardingJdbc使用java config的方式配置DataSource,并且添加@Primary注解标注该数据源。但是此时的Druid数据源也要配置,否则会报错。Mybatis自动配置类(MybatisAutoConfiguration
)会找标注有@Primary的数据源来进行注入。
ShardingJdbc兼容达梦配置问题
原因分析
当解决以上两个问题之后,项目启动报错,如下:
原因在于读取到的达梦版本号为:8…05134284132,且使用**分隔符“.”**解析获取到的版本号为空串(“”),强转Integer的时候报错。不同的版本情况不一样,不知道是否有存在解析不报错的版本。
而版本号8…05134284132 来自于查询该SQLselect top 1 banner, id_code from v$version where banner like 'DM Database Server%';
并解析获取,源码如下:
SQL查询结果如下:
解决办法
版本号既然是从数据库中通过语句来获取到的,版本号不可能随随便便修改,那如果我修改if (this.connection.compatibleOracle())
条件内容,使其返回1,问题不就解决了嘛?开搞!
而使方法this.connection.compatibleOracle()
满足条件,需要使其字段this.compatibleMode=1
,如下:
而该字段的值来源于DmdbConnection.setAttributes()
方法解析获得。如下:
所以在配置达梦url时,添加参数compatibleMode=oracle
,则版本解析报错的问题解决!
程序刚启动就报无效的表或视图名
报错条件
如果项目中有该配置spring.shardingsphere.sharding.default-data-source-name=ds0
或者spring.shardingsphere.datasource.names=ds0
只配置了一个数据源时(只有一个的时候,这个被默认成为了default-data-source-name
的值了),则启动的时候就报无效的表或视图名,是的,是启动的时候,如下:
原因分析
如果配置了default-data-source-name
,则会调用SchemaMetaDataLoader.load()
SchemaMetaDataLoader.load()
方法源码如下:
那如果我指定当前用户的schema
,那获取到的不就是我当前用户的所有表了吗,那后续执行的SQL不就不会出现不存在的表或视图了吗?然而,通过Connection.getSchema()
来获取是报错,获取不到的,最终被忽略的异常还是返回了null,返回了null,没有指定schema,最后的结果还是查询所有schema的所有表。
解决办法
删除spring.shardingsphere.sharding.default-data-source-name=ds0
配置,default-data-source-name
值为空,则走另外的分支,则不报错!
项目源代码
项目所涉及到的源代码由于提交记录,以及后续要继续提交,存在敏感信息,所以该仓库就不公开也不公布了,需要到原代码demo,请往此处下载(csdn改了,积分规则不能由自己设置了,变成动态分配了,所以改不了为0):ShardingJdbc兼容达梦demo
原创文章,转载请注明出处,侵权必究。