ShardingJdbc兼容达梦

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容器中会存在shardingDataSourcedataSource两个数据源。

在这里插入图片描述

在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

原创文章,转载请注明出处,侵权必究。

  • 28
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NPException.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值