nacos添加PostgreSQL支持

背景

由于项目中之前使用的是PostgreSQL,最近要添加nacos作为服务中心与注册中心来使用,可惜nacos不支持PostgreSQL,但又不想因此再引入Mysql增加复杂度。此修改保持了mysql与derby的可用性。

环境

使用nacos2.1.0,让其支持

  • postgresql14.x
  • mysql8.x
  • derby

步骤

1.下载nacos

笔者使用时,最新版是2.1.0,下载

git clone https://github.com/alibaba/nacos.git -b 2.1.0

得到如下文件
nacos项目

2. 添加PostgreSQL

修改共3处:

① /pom.xml

<properties>
···
<postgresql.version>42.3.3</postgresql.version>
···
</properties>

···

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>${postgresql.version}</version>
</dependency>

② /config/pom.xml

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
</dependency>

③ /naming/pom.xml

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
</dependency>

3. 添加PostgreSQL驱动代码

① PropertiesConstant.java

public static final String MYSQL = "mysql";

public static final String POSTGRESQL = "postgresql";

② PropertyUtil.java#loadSetting

// postgresql or mysql
final String platform = getString(PropertiesConstant.SPRING_DATASOURCE_PLATFORM, "");
setUseExternalDB(PropertiesConstant.MYSQL.equalsIgnoreCase(platform)
        || PropertiesConstant.POSTGRESQL.equalsIgnoreCase(platform));

③ ExternalDataSourceProperties.java

private static final String JDBC_DRIVER_NAME_MYSQL = "com.mysql.cj.jdbc.Driver";

private static final String JDBC_DRIVER_NAME_POSTGRESQL = "org.postgresql.Driver";

···

#build方法内

//Add PostgreSQL support
String driverClassName = JDBC_DRIVER_NAME_MYSQL;
if (PropertiesConstant.POSTGRESQL.equalsIgnoreCase(
        EnvUtil.getProperty(PropertiesConstant.SPRING_DATASOURCE_PLATFORM))) {
    driverClassName = JDBC_DRIVER_NAME_POSTGRESQL;
}

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);
    poolProperties.setDriverClassName(driverClassName);
    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();
    ds.setConnectionTestQuery(TEST_QUERY);
    ds.setIdleTimeout(TimeUnit.MINUTES.toMillis(10L));
    ds.setConnectionTimeout(TimeUnit.SECONDS.toMillis(3L));
    dataSources.add(ds);
    callback.accept(ds);
}

④ StartingApplicationListener.java

private static final String DATABASE_MYSQL = "mysql";

private static final String DATABASE_POSTGRESQL = "postgresql";

···

#judgeStorageMode方法内

// Add PostgreSQL support
final String platform = env.getProperty(DATASOURCE_PLATFORM_PROPERTY, DEFAULT_DATASOURCE_PLATFORM);
boolean useExternalStorage = (DATABASE_MYSQL.equalsIgnoreCase(platform)
        || DATABASE_POSTGRESQL.equalsIgnoreCase(platform));

4. 兼容PostgreSQL

① 主键

# 全局替换:
Statement.RETURN_GENERATED_KEYS 替换为 new String[]{"id"}

# 由于postgresql无法通过Statement.RETURN_GENERATED_KEYS获取主键,因此只能显示的指定要寻找的主键

② LIKE

当前2.1.0版本只有两个地方,都在/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/persistence下
① ExternalRolePersistServiceImpl#findRolesLikeRoleName
② ExternalUserPersistServiceImpl#findUserLikeUsername
like

#如上图类似替换
LIKE '%' ? '%' 替换成 LIKE ?
new String[] {username} 替换成 new String[] {String.format("%%%s%%", username)}

# LIKE '%' '%AD' '%'的方式,mysql可用,但并非标准sql
# LIKE '%%AD%'的方式,这是标准sql,因此mysql与postgresql都可使用

③ LIMIT

# 全局替换:
LIMIT ?, ?    替换为 OFFSET ? LIMIT ?
LIMIT ?,?     替换为 OFFSET ? LIMIT ?
LIMIT \\?,\\? 替换为 OFFSET \\? LIMIT \\?

# LIMIT ?,? 是mysql可用,但并非标准sql
# OFFSET ? LIMIT ? 是sql,因此mysql与postgresql都可使用

还有一个较为特殊
ExternalStoragePaginationHelperImpl#fetchPage

String selectSql;
if (isDerby()) {
    selectSql = sqlFetchRows + " OFFSET " + startRow + " ROWS FETCH NEXT " + pageSize + " ROWS ONLY";
} else if (lastMaxId != null) {
    // PostgreSQL support
    selectSql = sqlFetchRows + " AND id > " + lastMaxId + " ORDER BY id ASC" + " LIMIT " + pageSize + " OFFSET " + 0;
} else {
    // PostgreSQL support
    selectSql = sqlFetchRows + " LIMIT " + pageSize + " OFFSET " + startRow;
}

5. BUG处理

这部分是官方上的bug,已提交了ISSUE,并且也已解决,后续版本应该没问题,解决方式在ISSUE中也提到了

# 1. ExternalStoragePersistServiceImpl#findAllConfigInfoForDumpAll
params.toArray() 替换为 new Object[] {(pageNo - 1) * pageSize, pageSize}

# 2. EmbeddedStoragePersistServiceImpl#findAllConfigInfoForDumpAll
EMPTY_ARRAY 替换为 new Object[] {(pageNo - 1) * pageSize, pageSize}

6. 配置文件

剩下的就是

  1. application.properties
  2. nacos-postgresql.sql

的问题了

① application.properties

spring.datasource.platform=postgresql

db.url.0=jdbc:postgresql://127.0.0.1:5432/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=postgres
db.password.0=nacos

以上配置要类似如上进行修改

② nacos-postgresql.sql

官方提供的是mysql与derby版的,需要使用postgresql版的,在下面提供。

结语

以上已经做了打包,可在Github中下载,这份已做了如上的修改,也加上了日语翻译,如不需要,可下载获取nacos-postgresql.sql,再自行根据以上进行修改打包。

更新

2023.07.01

感谢@u012888682的指正,以上修改在mysql上无法使用。

# 全局替换:
OFFSET ? LIMIT ?
OFFSET \\? LIMIT \\?
# 以上在mysql并不可用

需再替换为
LIMIT ? OFFSET ?
LIMIT \\? OFFSET \\?
# 这个是才能兼容mysql与postgresql
# 记得将相应的参数位置对调
  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 20
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值