Nacos2.2.0适配金仓Kingbase8数据源
Nacos 从 2.2.0 版本开始,可通过 SPI 机制注入多数据源实现插件,并在引入对应数据源实现后,便可在 Nacos 启动时通过读取 application.properties 配置文件中 spring.datasource.platform 配置项选择加载对应多数据源插件.
Nacos 官方默认实现 MySQL、Derby ,其他类型数据库接入需要参考下文自己扩展。
文章目录
一、Nacos官方文档
Nacos整体介绍可看Nacos官方文档
二、实现步骤
下面,重点讲解如何通过修改源码实现金仓KINGBASE8适配
2.1 2.2.0版本源码下载
2.2 引入Kingbase8驱动包
根据适配版本选择对应驱动包
2.2.1 nacos-all pom.xml
<kingbase-connector-java.version>8.6.0</kingbase-connector-java.version>
<dependency>
<groupId>com.kingbase8</groupId>
<artifactId>kingbase8</artifactId>
<version>${kingbase-connector-java.version}</version>
</dependency>
2.2.2 nacos-config pom.xml
<dependency>
<groupId>com.kingbase8</groupId>
<artifactId>kingbase8</artifactId>
</dependency>
2.3 nacos-config模块修改
修改类config/src/main/java/com/alibaba/nacos/config/server/service/datasource/ExternalDataSourceProperties.java
修改后的代码如下:
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.alibaba.nacos.config.server.service.datasource;
import com.alibaba.nacos.common.utils.Preconditions;
import com.alibaba.nacos.common.utils.StringUtils;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.core.env.Environment;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static com.alibaba.nacos.common.utils.CollectionUtils.getOrDefault;
/**
* Properties of external DataSource.
*
* @author Nacos
*/
public class ExternalDataSourceProperties {
private String jdbcDriverName = "com.kingbase8.Driver";
private String testQuery = "SELECT 1";
private Integer num;
private List<String> url = new ArrayList<>();
private List<String> user = new ArrayList<>();
private List<String> password = new ArrayList<>();
public void setNum(Integer num) {
this.num = num;
}
public void setUrl(List<String> url) {
this.url = url;
}
public void setUser(List<String> user) {
this.user = user;
}
public void setPassword(List<String> password) {
this.password = password;
}
/**
* Build serveral HikariDataSource.
*
* @param environment {
@link Environment}
* @param callback Callback function when constructing data source
* @return List of {
@link HikariDataSource}
*/
List<HikariDataSource> build(Environment environment, Callback<HikariDataSource> callback) {
List<HikariDataSource> dataSources = new ArrayList<>();
Binder.get(environment).bind("db", Bindable.ofInstance(this));
Preconditions.checkArgument(Objects.nonNull(num), "db.num is null");
Preconditions.checkArgument(CollectionUtils.isNotEmpty(user), "db.user or db.user.[index] is null");
Preconditions.checkArgument(CollectionUtils.isNotEmpty(password), "db.password or db.password.[index] is null");
for (int index = 0; index < num; index++) {
int currentSize = index + 1;
Preconditions.checkArgument(url.size() >= currentSize, "db.url.%s is null", index);
DataSourcePoolProperties poolProperties = DataSourcePoolProperties.build(environment);
if (StringUtils.isEmpty(poolProperties.getDataSource().getDriverClassName())) {
poolProperties.setDriverClassName(jdbcDriverName);
}
poolProperties.setJdbcUrl(url.get(index).trim());
poolProperties.setUsername(getOrDefault(user, index, user.get(0)).trim());
poolProperties.setPassword(getOrDefault(password, index, password.get(0)).trim());
HikariDataSource ds = poolProperties.getDataSource();
if (StringUtils.isEmpty(ds.getConnectionTestQuery())) {
ds.setConnectionTestQuery(testQuery);
}
dataSources.add(ds);
callback.accept(ds);
}
Preconditions.checkArgument(CollectionUtils.isNotEmpty(dataSources), "no datasource available");
return dataSources;
}
interface Callback<D> {
/**
* Perform custom logic.
*
* @param datasource dataSource.
*/
void accept(D datasource);
}
}
2.4 nacos-datasource-plugin模块修改
2.4.1 DataSourceConstant类修改
修改类:plugin/datasource/src/main/java/com/alibaba/nacos/plugin/datasource/constants/DataSourceConstant.java
修改后的代码如下:
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.plugin.datasource.constants;
/**
* The data source name.
*
* @author czf
**/
public class DataSourceConstant {
public static final String MYSQL = "mysql";
public static final String DERBY = "derby";
public static final String KINGBASE = "kingbase8";
}
2.4.2 增加KINGBASE8的mapper实现类
先上截图,如下新增10个类:
在plugin/datasource/src/main/java/com/alibaba/nacos/plugin/datasource/impl/目录新建kingbase目录,再在dm目录新增实现类,各个类代码如下:
1、KingbaseAbstractMapper
package com.alibaba.nacos.plugin.datasource.impl.kingbase;
import com.alibaba.nacos.plugin.datasource.mapper.AbstractMapper;
import java.util.List;
/**
* @author czf
*/
public abstract class KingbaseAbstractMapper extends AbstractMapper {
@Override
public String select(List<String> columns, List<String> where) {
StringBuilder sql = new StringBuilder("SELECT ");
for (int i = 0; i < columns.size(); i++) {
sql.append(columns.get(i));
if (i == columns.size() - 1) {
sql.append(" ");
}
else {
sql.append(",");
}
}
sql.append("FROM ");
sql.append(getTableName());
sql.append(" ");
if (where.size() == 0) {
return sql.toString();
}
sql.append("WHERE ");
for (int i = 0; i < where.size(); i++) {
String column = where.get(i);
// 租户列特殊处理 避免前端传空字符串是Oracle查询不到数据
if ("tenant_id".equalsIgnoreCase(column)) {
sql.append("(");
sql.append(column).append(" = ").append("?");
sql.append(" OR ");
sql.append(column).append(" IS NULL ");
sql.append(")");
}
else {
sql.append(column).append(" = ").append("?");
}
if (i != where.size() - 1) {
sql.append(" AND ");
}
}
return sql.toString();
}
@Override
public String update(List<String> columns, List<String> where) {
StringBuilder sql = new StringBuilder();
String method = "UPDATE ";
sql.append(method);
sql.append(getTableName()).append(" ").append("SET ");
for (int i = 0; i < columns.size(); i++) {
sql.append(columns.get(i)).append(" = ").append("?");
if (i != columns.size() - 1) {
sql.append(",");
}
}
if (where.size() == 0) {
return sql.toString();
}
sql.append(" WHERE ");
for (int i = 0; i < where.size(); i++) {
String column = where.get(i);
if ("tenant_id".equalsIgnoreCase(column)) {
sql.append("(");
sql.append(column).append(" = ").append("?");
sql.append(" OR ");
sql.append(column).append(" IS NULL ");
sql.append(")");
}
else {
sql.append(column).append(" = ").append("?");
}
if (i != where.size() - 1) {
sql.append(" AND ");
}
}
return sql.toString();
}
@Override
public String delete(List<String> params)