
# 通过JDBC连接HTAP标准版实例
本章节介绍通过JDBC连接HTAP标准版实例的方法。
#### 注意事项
目前HTAP实例只支持UTF-8字符集。
#### 前提条件
- 用户需要具备以下技能：
  - 熟悉计算机基础知识。
  
  - 了解Java编程语言。
  
  - 了解JDBC基础知识。
   

- 下载官方MySQL或MariaDB的JDBC驱动。
- 已创建标准版HTAP实例。
- 添加依赖至pom.xml。
  ```
  <dependency>   
      <groupId>mysql</groupId>   
      <artifactId>mysql-connector-java</artifactId>   
      <version>5.1.47</version> 
  </dependency>
  ```
  
 
#### 通过JDBC连接HTAP标准版实例
- [使用SSL证书连接]
  
  使用SSL证书连接实例，即通过证书校验并连接数据库。
  1. [登录TaurusDB管理控制台](https://console.huaweicloud.com/gaussdbformysql/#/management/list)。
  
  2. 在"实例管理"页面的实例列表中，选择目标TaurusDB实例，单击实例名称，进入实例概览页面。
  
  3. 在左侧导航栏选择"HTAP实时分析"。
  
  4. 选择目标HTAP实例，单击实例名称，进入"基本信息"页面。
  
  5. 在"实例信息"区域，单击"SSL"处的"下载"。
  
  6. 使用keytool工具通过CA证书生成truststore文件。
     
     ```
     <keytool工具的安装路径> ./keytool.exe -importcert -alias <MySQLCACert> -­file <ca.pem> -keystore <truststore_file> -storepass <password>
     ```
     表1变量说明 
     | 变量                    | 说明                                                                      |
     |:---|:---|
     | *\<keytool工具的安装路径\>*  | 请替换为JDK或JRE安装路径的bin目录，例如C:\\Program Files (x86)\\Java\\jdk­11.0.7\\bin。 |
     | *\<MySQLCACert\>*     | 请设置truststore文件的名称。建议设置为具有业务意义的名称，便于后续识别。                               |
     | *\<ca.pem\>*          | 请替换为下载解压后CA证书的名称，例如ca.pem。                                              |
     | *\<truststore_file\>* | 请设置truststore文件的存放路径。                                                   |
     | *\<password\>*        | 请设置truststore文件的密码。                                                     |
        
     代码示例（使用JDK安装路径下的keytool工具生成truststore文件）：
     ```
     Owner:  CN=MySQL_Server_8.0.22_Auto_Generated_CA_Certificate
     Issuer: CN=MySQL_Server_8.0.22_Auto_Generated_CA_Certificate 
     Serial number: 1
     Valid from: Thu Feb 16 11:42:43 EST 2017 until: Sun Feb 14 11:42:43 EST 2027 
     Certificate fingerprints:
          MD5: 18:87:97:37:EA:CB:0B:5A:24:AB:27:76:45:A4:78:C1
          SHA1: 2B:0D:D9:69:2C:99:BF:1E:2A:25:4E:8D:2D:38:B8:70:66:47:FA:ED 
          SHA256:C3:29:67:1B:E5:37:06:F7:A9:93:DF:C7:B3:27:5E:09:C7:FD:EE:2D:18:86:F4:9C:40:D8:26:CB:DA:95: A0:24
          Signature algorithm name: SHA256withRSA Subject Public Key Algorithm: 2048-bit RSA key 
          Version: 1
          Trust this certificate? [no]: y
          Certificate was added to keystore
     ```
     
     
  
  7. 通过JDBC连接数据库，代码中的JDBC链接格式如下： 
     ```
     jdbc:mysql://<instance_ip>:<instance_port>/<database_name>? 
     requireSSL=<value1>&useSSL=<value2>&verifyServerCertificate=<value3>&trustCertificateKeyStoreUrl=file: 
     <truststore_file>&trustCertificateKeyStorePassword=<password>
     ```
     表2参数说明 
     | 参数                    | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
     |:---|:---|
     | *\<instance_ip\>*     | 请替换为HTAP实例的IP地址。 说明： - 如果通过弹性云服务器连接，"instance_ip"是HTAP实例的"读写内网地址"。您可以在该基本信息页面的"网络信息"区域查看。  - 如果开启了数据库代理，通过数据库代理连接HTAP实例时，此处的IP为数据库代理地址。您可以在数据库代理页面查看代理地址。                                                                                                                                                                                                   |
     | *\<instance_port\>*   | 请替换为实例的数据库端口，默认为3306。 说明： 您可以在该基本信息页面的"网络信息"区域查看。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
     | *\<database_name\>*   | 请替换为连接实例使用的数据库名。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
     | *\<value1\>*          | requireSSL的值，用于设置服务端是否支持SSL连接。取值如下： - true：支持。  - false：不支持。   说明： requireSSL与其他连接参数、sslMode之间的关系请参考[表3]。                          |
     | *\<value2\>*          | useSSL的值，用于设置客户端是否使用SSL连接服务端。取值如下： - true：使用。  - false：不使用。 说明： useSSL与其他连接参数、sslMode之间的关系请参考[表3]。                        |
     | *\<value3\>*          | verifyServerCertificate的值，客户端是否校验服务端的证书。取值如下： - true：校验。  - false：不校验。 说明： verifyServerCertificate与其他连接参数、sslMode之间的关系请参考[表3]。    |
     | *\<truststore_file\>* | 请替换为[6]中为truststore文件设置的存储路径。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
     | *\<password\>*        | 请替换为[6]中为truststore文件设置的密码。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
        
     根据客户端使用的Jar包不同，指定对应参数值进行连接。示例如下：
     - mysql-connector-java-5.1.*xx* .jar（对于8.0.28以前版本的连接驱动，使用enabledTLSProtocols参数，详情请参考[官方文档](https://dev.mysql.com/doc/connector-j/en/connector-j-reference-using-ssl.html)。）
       ```
       jdbc:mysql://<instance_ip>:<instance_port>/<database_name>? 
        requireSSL=true&useSSL=true&verifyServerCertificate=true&trustCertificateKeyStoreUrl=file: 
        <truststore_file>&trustCertificateKeyStorePassword=<password>&enabledTLSProtocols=TLSv1.2
       ```
       
     
     - mysql-connector-java-8.0.*xx* .jar（对于8.0.28及以后版本的连接驱动，使用tlsVersions参数）
       ```
       jdbc:mysql://<instance_ip>:<instance_port>/<database_name>? 
        requireSSL=true&useSSL=true&verifyServerCertificate=true&trustCertificateKeyStoreUrl=file: 
        <truststore_file>&trustCertificateKeyStorePassword=<password>&tlsVersions=TLSv1.2
       ```
       
     
     
      表3连接参数与SSLMode的关系说明 
     | useSSL | requireSSL | verifyServerCertificate | sslMode   |
     |:---|:---|:---|:---|
     | false  | 不涉及        | 不涉及                     | DISABLED  |
     | true   | false      | false                   | PREFERRED |
     | true   | true       | false                   | REQUIRED  |
     | true   | 不涉及        | true                    | VERIFY_CA |
        
     代码示例如下（连接HTAP数据库的java代码）：
     ```
     import java.sql.Connection;
     import java.sql.DriverManager;
     import java.sql.ResultSet;
     import java.sql.Statement;
     import java.sql.SQLException;
     public class JDBCTest {
         static final String IP = "*.*.*.*"; //实例的IP地址
         static final String USER = "***";           //用户名
         static final String PASS = "***";           //密码
         public static void main(String[] args) {
             System.out.println("JDBCTest.main");
             Connection conn = null;
             Statement stmt = null;
             //sslMode:VERIFY_CA
             String url = "jdbc:mysql://" + IP + ":<port>/<database>?useSSL=true&verifyServerCertificate=true&&enabledTLSProtocols=TLSv1.2,TLSv1.3&trustCertificateKeyStoreUrl=file:<truststore_file>&trustCertificateKeyStorePassword=<password>";
             //sslMode:PREFERRED
             //String url = "jdbc:mysql://" + IP + ":<port>/<database>?requireSSL=false&useSSL=true&verifyServerCertificate=false&enabledTLSProtocols=TLSv1.2,TLSv1.3";
             //sslMode:REQUIRED
             //String url = "jdbc:mysql://" + IP + ":<port>/<database>?requireSSL=true&useSSL=true&verifyServerCertificate=false&enabledTLSProtocols=TLSv1.2,TLSv1.3";
             try {
                 //Class.forName("com.mysql.jdbc.Driver");
                 Class.forName("com.mysql.cj.jdbc.Driver");
                 conn = DriverManager.getConnection(url, USER, PASS);
                 stmt = conn.createStatement();
                 String sql = "show databases;";
                 ResultSet rs = stmt.executeQuery(sql);
                 int columns = rs.getMetaData().getColumnCount();
                 for (int i = 1; i <= columns; i++) {
                     System.out.print(rs.getMetaData().getColumnName(i));
                     System.out.print("\t");
                 }
                 while (rs.next()) {
                     System.out.println();
                     for (int i = 1; i <= columns; i++) {
                         System.out.print(rs.getObject(i));
                         System.out.print("\t");
                     }
                 }
                 rs.close();
                 stmt.close();
                 conn.close();
             } catch (SQLException se) {
                 se.printStackTrace();
             } catch (Exception e) {
                 e.printStackTrace();
             } finally {
                 // release resource ....
             }
         }
     }
     ```
     
     
   
- [无证书连接]
  
  代码中的JDBC链接格式如下:
  ```
  jdbc:mysql://<instance_ip>:<instance_port>/<database_name>
  ```
  表4参数说明 
  | **参数**            | **说明**                                    |
  |:---|:---|
  | \<instance_ip\>   | HTAP实例中FE节点的IP地址。若开启了数据库代理，请使用数据库代理的IP地址。 |
  | \<instance_port\> | HTAP实例端口，默认为3306。                         |
  | \<database_name\> | 请替换为连接实例使用的数据库名。                          |
     
  代码示例如下（连接HTAP数据库的java代码）：
  ```
  import java.sql.Connection;
  import java.sql.DriverManager;
  import java.sql.ResultSet;
  import java.sql.Statement;
  import java.sql.SQLException;
  public class JDBCTest {
      static final String IP = "*.*.*.*"; //实例的IP地址
      static final String USER = "***";           //用户名
      static final String PASS = "***";           //密码
      public static void main(String[] args) {
          Connection conn = null;
          Statement stmt = null;
          String url = "jdbc:mysql://" + IP + ":<port>/<database>";
          try {
              
              Class.forName("com.mysql.jdbc.Driver");
              conn = DriverManager.getConnection(url, USER, PASS);
              stmt = conn.createStatement();
              String sql = "show databases;";
              ResultSet rs = stmt.executeQuery(sql);
              int columns = rs.getMetaData().getColumnCount();
              for (int i = 1; i <= columns; i++) {
                  System.out.print(rs.getMetaData().getColumnName(i));
                  System.out.print("\t");
              }
              while (rs.next()) {
                  System.out.println();
                  for (int i = 1; i <= columns; i++) {
                      System.out.print(rs.getObject(i));
                      System.out.print("\t");
                  }
              }
              rs.close();
              stmt.close();
              conn.close();
          } catch (SQLException se) {
              se.printStackTrace();
          } catch (Exception e) {
              e.printStackTrace();
          } finally {
              // release resource ....
          }
      }
  }
  ```
