【GaussDB】使用MySQL客户端连接到GaussDB的M-Compatibility数据库

概述

GaussDB 从内核 505.1 版本(2024年4月发布)起,新增了一种新的兼容模式 M-Compatibility,这是一种整体上比之前的B模式对MySQL兼容性更高的模式。这种M模式在建库时会自动使用模板库 templatem。

之所以需要再新增一种M模式,我猜测是因为GaussDB发现有些MySQL兼容性已经完全违背了内核的SQL及存储逻辑,无法通过参数调整进行兼容,为了不影响原有B模式的用户,必须新增一种兼容模式来隔离之前的逻辑。

新的这个M兼容模式,可以用MySQL客户端进行连接,但是实际使用过程中,可能会有一些坑在文档中并未详细说明,本文就来介绍一下"使用MySQL客户端连接到GaussDB的M-Compatibility数据库"的正确姿势。

测试环境:本文使用的GaussDB内核版本为 506.0 SPC0100

建库操作

指定M兼容模式建库:

CREATE DATABASE mysql DBCOMPATIBILITY='M';

修改参数

参考文档

《基于MySQL JDBC开发-开发步骤-环境准备》

添加客户端IP到数据库白名单

将客户端IP添加到数据库白名单,具体操作请联系管理员处理。

设置兼容性参数

请参见《管理员指南》中的"配置运行参数"章节,配置相关GUC参数并重启数据库。

参数配置:

1、配置协议监听的TCP端口号,设置GUC参数 plat_compat_server_port 为合理端口

2、如果使用到RSA,需要设置GUC参数 plat_compat_allow_public_key_retrieval 为 on

3、将GUC参数 m_format_dev_version 设置为 "s2"

执行命令:

css 复制代码
gs_guc reload -I all -N all -c "plat_compat_server_port=3306"
gs_guc reload -I all -N all -c "plat_compat_allow_public_key_retrieval=on"
gs_guc reload -I all -N all -c "m_format_dev_version='s2'"

创建连接用户(可选)

CREATE USER mysql_user PASSWORD 'Gaussdb@123' SYSADMIN MONADMIN;

连接测试

初始连接问题

使用MySQL客户端连接时出现报错:

错误信息: plat_compat_b_conn_handshake, handshake error.

Java代码连接测试

尝试手写一段Java代码进行连接:

css 复制代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

public class MySQLCreateTable {
    public static void main(String[] args) {
        String url = "jdbc:mysql://192.168.163.119:3306/mysql";
        String user = "mysql_user";
        String password = "Gaussdb@123";

        try (Connection conn = DriverManager.getConnection(url, user, password);
             Statement stmt = conn.createStatement()) {

            String sql = "CREATE TABLE IF NOT EXISTS users2 (" +
                         "id INT PRIMARY KEY AUTO_INCREMENT," +
                         "name VARCHAR(100) NOT NULL," +
                         "email VARCHAR(100) NOT NULL UNIQUE" +
                         ")";
            stmt.executeUpdate(sql);
            System.out.println("Table created successfully.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行结果: 也报错了

com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications

link failure

The last packet sent successfully to the server was 0 milliseconds

ago. The driver has not received any packets from the server.

at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:174)

at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64)

at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:827)

at com.mysql.cj.jdbc.ConnectionImpl.(ConnectionImpl.java:447)

at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:237)

at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:199)

at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:681)

at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:229)

at MySQLCreateTable.main(MySQLCreateTable.java:11) Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link

failure

The last packet sent successfully to the server was 0 milliseconds

ago. The driver has not received any packets from the server.

at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native

Method)

at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)

at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)

at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)

at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)

at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:61)

at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:105)

at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:151)

at com.mysql.cj.exceptions.ExceptionFactory.createCommunicationsException(ExceptionFactory.java:167)

at com.mysql.cj.protocol.a.NativeProtocol.negotiateSSLConnection(NativeProtocol.java:340)

at com.mysql.cj.protocol.a.NativeAuthenticationProvider.negotiateSSLConnection(NativeAuthenticationProvider.java:777)

at com.mysql.cj.protocol.a.NativeAuthenticationProvider.proceedHandshakeWithPluggableAuthentication(NativeAuthenticationProvider.java:486)

at com.mysql.cj.protocol.a.NativeAuthenticationProvider.connect(NativeAuthenticationProvider.java:202)

at com.mysql.cj.protocol.a.NativeProtocol.connect(NativeProtocol.java:1348)

at com.mysql.cj.NativeSession.connect(NativeSession.java:163)

at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:947)

at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:817)

... 6 more Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are

inappropriate)

at java.base/sun.security.ssl.HandshakeContext.(HandshakeContext.java:172)

at java.base/sun.security.ssl.ClientHandshakeContext.(ClientHandshakeContext.java:103)

at java.base/sun.security.ssl.TransportContext.kickstart(TransportContext.java:240)

at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:448)

at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:426)

at com.mysql.cj.protocol.ExportControlled.performTlsHandshake(ExportControlled.java:316)

at com.mysql.cj.protocol.StandardSocketFactory.performTlsHandshake(StandardSocketFactory.java:188)

at com.mysql.cj.protocol.a.NativeSocketConnection.performTlsHandshake(NativeSocketConnection.java:99)

at com.mysql.cj.protocol.a.NativeProtocol.negotiateSSLConnection(NativeProtocol.java:331)

... 13 more

解决方案

查看官方文档《基于MySQL JDBC开发-开发步骤-连接数据库-以常规方式连接》,发现文档中的连接串是:

String sourceURL =

"jdbc:mysql://ip:ip:ip:port/database?useSSL=false&allowPublicKeyRetrieval=true";

多了两个参数,逐步测试:

步骤1:添加 useSSL=false

先加一个 useSSL=false 参数测试。

结果: 出现了和mogeaver一样的报错。

步骤2:添加 allowPublicKeyRetrieval=true

再把另一个参数也加上去 allowPublicKeyRetrieval=true。

结果: ✅ 执行成功了!

验证其他客户端

在mogeaver里也加上这个参数 allowPublicKeyRetrieval=true。

结果: ✅ 也连接成功了!

说明:

但是mogeaver里的useSSL为true,之所以没有报错,是因为mogeaver里还自动加上了enabledTLSProtocols=TLSv1,TLSv1.1,TLSv1.2

连接参数总结

根据测试,自己写的Java代码,连接时必须加上:

方案一: useSSL=false&allowPublicKeyRetrieval=true

方案二: useSSL=true&enabledTLSProtocols=TLSv1,TLSv1.1,TLSv1.2

常见问题及解决

如果是普通的测试人员,测到这里,就会认为连接测试这一项已经测试通过了,但是换几个不同的环境里的GaussDB去测,还可能会出现这样的报错:

问题:Access denied for user

错误信息: Access denied for user

注意: 如果是用户名密码错误,也会报这个错,所以先要用gsql测试一下用户名密码是否正确,确认用户名密码没有写错后,那么问题就可能发生在密码加密方式上。

原因分析

在官方文档[《配置客户端接入认证》](https://support.huawei.com/carrier/docview?nid=DOC1101458028\&path=PBI1-253383977/PBI1-23710112/PBI1-23710137/PBI1-256197501\&partNo=k00e)这个章节里写着:

外部客户端使用M-Compatibility兼容协议远程连接M-Compatibility数据库时,只支持 sha256认证方式

于是去检查gs_hba.conf,发现无论是配置成md5还是sha256,Access denied for user这个问题都依然存在。

然后继续翻官方文档,发现在《设置密码安全策略》这个章节里写着:

使用M-Compatibility兼容协议连接数据库时,仅支持sha256加密模式,即 password_encryption_type =

2

也就是说,必须确保数据库用户的密码存储时,必须是仅存储sha256密文,不能支持其他方式。

解决步骤

1、修改密码加密参数:

gs_guc reload -I all -N all -c "password_encryption_type=2"

2、重新设置用户密码:

ALTER USER mysql_user PASSWORD 'mysql_123';

到此,使用MySQL客户端连接GaussDB就顺利了...吗?

进阶配置:RSA加密支持

搜索官方文档,发现还有这么一个章节:《使用RSA加密登录密码》

RSA加密登录配置要求:

设置 plat_compat_allow_public_key_retrieval 参数值为 on 设置 require_ssl 参数值为

off 设置 hba type 参数值为 host 或 hostnossl

也就是说,如果 require_ssl 为 on,那么本文的配置方式也会连接不上去了。

补充说明

另外,数据库里还有个参数 plat_compat_default_database,可以配置MySQL协议连过来需要连接哪个库。

在没有设置这个参数时: JDBC连接串里的dbname就真的是GaussDB里面的数据库名称

如果设置了这个参数: JDBC连接串里的dbname就是 plat_compat_default_database 指定的库下的schema名称

相关推荐
m0_748248021 小时前
Redis 简介与安装指南
数据库·redis·缓存
Elastic 中国社区官方博客6 小时前
在 Elasticsearch 中使用 Mistral Chat completions 进行上下文工程
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
编程爱好者熊浪7 小时前
两次连接池泄露的BUG
java·数据库
南宫乘风8 小时前
基于 Flask + APScheduler + MySQL 的自动报表系统设计
python·mysql·flask
TDengine (老段)9 小时前
TDengine 字符串函数 CHAR 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
qq7422349849 小时前
Python操作数据库之pyodbc
开发语言·数据库·python
姚远Oracle ACE10 小时前
Oracle 如何计算 AWR 报告中的 Sessions 数量
数据库·oracle
Dxy123931021610 小时前
MySQL的SUBSTRING函数详解与应用
数据库·mysql
码力引擎10 小时前
【零基础学MySQL】第十二章:DCL详解
数据库·mysql·1024程序员节
杨云龙UP10 小时前
【MySQL迁移】MySQL数据库迁移实战(利用mysqldump从Windows 5.7迁至Linux 8.0)
linux·运维·数据库·mysql·mssql