更新时间:2024-05-14 GMT+08:00

使用JDBC连接数据库

JDBC(Java Database Connectivity,Java数据库连接)是用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问接口,应用程序可基于它操作数据。GaussDB库提供了对JDBC 4.2特性的支持,需要使用JDK1.8版本编译程序代码,不支持JDBC桥接ODBC方式。

前提条件

计算机已安装Java JDK8版本。

JDBC包

包名为GaussDB-Kernel_数据库版本号_操作系统版本号_64bit_Jdbc.tar.gz。解压后JDBC的驱动jar包:
  • gaussdbjdbc.jar:主类名为“com.huawei.gaussdb.jdbc.Driver”,数据库连接的url前缀为“jdbc:gaussdb”,推荐使用此驱动包。本章的Java代码示例默认使用gaussdbjdbc.jar包。
  • gscejdbc.jar:主类名为“com.huawei.gaussdb.jdbc.Driver”,数据库连接的url前缀为“jdbc:gaussdb”,此驱动包打包了密态数据库需要加载的加解密相关的依赖库,密态场景推荐使用此驱动包。目前仅支持EulerOS操作系统。
  • gaussdbjdbc-JRE7.jar:主类名为“com.huawei.gaussdb.jdbc.Driver”,数据库连接的url前缀为“jdbc:gaussdb”,在JDK1.7环境使用gaussdbjdbc-JRE7.jar包。
  • 使用gscejdbc.jar驱动包时,需要先设置环境变量LD_LIBRARY_PATH。具体使用方式见《特性指南》中“设置密态等值查询 > 使用JDBC操作密态数据库”章节。
  • 在JDK1.8环境中使用gaussdbjdbc.jar,不推荐使用gaussdbjdbc-JRE7.jar。
  • 其他JDBC的jar包介绍请参考《开发指南》中“应用程序开发教程 > JDBC兼容性包”章节。

驱动类

在创建数据库连接之前,需要加载数据库驱动类“com.huawei.gaussdb.jdbc.Driver”。

  1. 由于GaussDB在JDBC的使用上与PG的使用方法保持兼容,所以同时在同一进程内使用两个JDBC驱动的时候,可能会造成类名冲突。
  2. GaussDB JDBC驱动主要做了以下特性的增强:
    1. 支持SHA256加密方式登录。
    2. 支持对接实现sf4j接口的第三方日志框架。
    3. 支持容灾切换。

环境类

客户端需配置JDK1.8。JDK是跨平台的,支持Windows、Linux等多种平台,下面以Windows为例,配置方法如下:

  1. DOS窗口(windows下的命令提示符)输入“java -version”,查看JDK版本,确认为JDK1.8版本。如果未安装JDK,请从官方网站下载安装包并安装。
  2. 根据如下步骤配置系统环境变量。

    1. 右键单击“我的电脑”,选择“属性”
    2. “系统”页面左侧导航栏单击“高级系统设置”
    3. “系统属性”页面,“高级”页签上单击“环境变量”
    4. “环境变量”页面上,“系统变量”区域单击“新建”“编辑”配置系统变量。变量说明如表1所示。
      表1 变量说明

      变量名

      操作

      变量值

      JAVA_HOME

      • 若存在,则单击“编辑”。
      • 若不存在,则单击“新建”。

      JAVA的安装目录。

      例如:C:\Program Files\Java\jdk1.8.0_131。

      Path

      单击“编辑”。

      • 若配置了JAVA_HOME,则在变量值的最前面加上: %JAVA_HOME%\bin。
      • 若未配置JAVA_HOME,则在变量值的最前面加上 JAVA安装的全路径:

        C:\Program Files\Java\jdk1.8.0_131\bin。

      CLASSPATH

      单击“新建”。

      %JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar。

加载驱动

在创建数据库连接之前,需要先加载数据库驱动程序。

加载驱动有两种方法:
  • 在代码中创建连接之前任意位置隐含装载:Class.forName("com.huawei.gaussdb.jdbc.Driver");。
  • 在JVM启动时参数传递:java -Djdbc.drivers=com.huawei.gaussdb.jdbc.Driver jdbctest。

    上述jdbctest为测试用例程序的名称。

函数原型

JDBC提供了三个方法,用于创建数据库连接。
  • DriverManager.getConnection(String url)。
  • DriverManager.getConnection(String url, Properties info)。
  • DriverManager.getConnection(String url, String user, String password)。

参数

表2 数据库连接参数

参数

描述

url

gaussdbjdbc.jar数据库连接描述符。

host为服务器名称或IPv4时,格式如下:

  • jdbc:gaussdb:(数据库名称缺省则与用户名一致)
  • jdbc:gaussdb:database
  • jdbc:gaussdb://host/database
  • jdbc:gaussdb://host:port/database
  • jdbc:gaussdb://host:port/database?param1=value1&param2=value2
  • jdbc:gaussdb://host1:port1,host2:port2/database?param1=value1&param2=value2

host为IPv6时,格式如下:

  • jdbc:gaussdb:(数据库名称缺省则与用户名一致)
  • jdbc:gaussdb:database
  • jdbc:gaussdb://host/database 或 jdbc:gaussdb://[host]/database
  • jdbc:gaussdb://[host]:port/database
  • jdbc:gaussdb://[host]:port/database?param1=value1&param2=value2
  • jdbc:gaussdb://[host1]:port1,[host2]:port2/database?param1=value1&param2=value2
说明:
  • database为要连接的数据库名称。
  • host为数据库服务器名称或IP地址,同时支持IPv4和IPv6。

    由于安全原因,数据库主节点禁止数据库内部其他节点无认证接入。如果要在数据库内部访问数据库主节点,请将JDBC程序部署在数据库主节点所在机器,host使用“127.0.0.1”。否则可能会出现“FATAL: Forbid remote connection with trust method!”错误。

    建议业务系统单独部署在数据库外部,否则可能会影响数据库运行性能。

    缺省情况下,连接服务器为localhost。

  • port为数据库服务器端口。

    缺省情况下,会尝试连接到5432端口的database。

  • 当host为IPv6且在url中指定port时,需要通过“[]”分隔IP,如:[IP]:port。
  • param为参数名称,即数据库连接属性。

    参数可以配置在URL中,以“?”开始配置,以“=”给参数赋值,以“&”作为不同参数的间隔。也可以采用info对象的属性方式进行配置,详情见示例

  • value为参数值,即数据库连接属性值。
  • 连接时需配置connectTimeout、socketTimeout,如果未配置,默认为0,即不会超时。在DN与客户端出现网络故障时,客户端一直未收到DN侧ACK确认报文,会启动超时重传机制,不断的进行重传。当超时时间达到系统默认的600s后才会报超时错误,这会导致RTO时间很高。
  • 建议使用JDBC标准接口建立连接时,确保url格式的合法性,不合法的url会导致异常,且异常中包含原始url字符串,可能造成敏感信息泄漏。

info

info常用属性详情请参见《开发指南》应用程序开发教程>基于JDBC开发>连接数据库章节参数说明。

user

数据库用户。

password

数据库用户的密码。

uppercaseAttributeName参数开启后,如果数据库中有小写、大写和大小写混合的元数据,只能查询出小写部分的元数据,并以大写的形式输出,使用前请务必确认元数据的存储是否全为小写以避免数据出错。

示例

示例1:连接数据库

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//以下代码将获取数据库连接操作封装为一个接口,可通过给定用户名和密码来连接数据库。
public static Connection getConnect(String username, String passwd)
    {
        //驱动类。
        String driver = "com.huawei.gaussdb.jdbc.Driver";
        //数据库连接描述符。
        String sourceURL = "jdbc:gaussdb://$ip:$port/database";
        Connection conn = null;
        
        try
        {
            //加载驱动。
            Class.forName(driver);
        }
        catch( Exception e )
        {
            e.printStackTrace();
            return null;
        }
        
        try
        {
             //创建连接。
            conn = DriverManager.getConnection(sourceURL, username, passwd);
            System.out.println("Connection succeed!");
        }
        catch(Exception e)
        {
            e.printStackTrace();
            return null;
        }
        
        return conn;
    }

示例2:使用Properties对象作为参数建立连接

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 以下代码将使用Properties对象作为参数建立连接。
public static Connection getConnectUseProp(String username, String passwd)
    {
        //驱动类。
        String driver = "com.huawei.gaussdb.jdbc.Driver";
        //数据库连接描述符。
        String sourceURL = "jdbc:gaussdb://$ip:$port/database?";
        Connection conn = null;
        Properties info = new Properties();
        
        try
        {
            //加载驱动。
            Class.forName(driver);
        }
        catch( Exception e )
        {
            e.printStackTrace();
            return null;
        }
        
        try
        {
             info.setProperty("user", username);
             info.setProperty("password", passwd);
             //创建连接。
             conn = DriverManager.getConnection(sourceURL, info);
             System.out.println("Connection succeed!");
        }
        catch(Exception e)
        {
            e.printStackTrace();
            return null;
        }
        
        return conn;
    }

常用参数详细请见《开发指南》中“应用程序开发教程>基于JDBC开发>JDBC常用参数参考”。

示例3:使用流式读功能

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// 认证用的用户名和密码直接写到代码中有很大的安全风险,建议在配置文件或者环境变量中存放(密码应密文存放,使用时解密),确保安全。
// 本示例以用户名和密码保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量(环境变量名称请根据自身情况进行设置)EXAMPLE_USERNAME_ENV和EXAMPLE_PASSWORD_ENV。
// 建立连接。
public static Connection getConnection(String username, String passwd) {
    String driver = "com.huawei.gaussdb.jdbc.Driver";
    String sourceURL = "jdbc:gaussdb://$ip:$port/database?enableStreamingQuery=true";
    Connection conn = null;
    try {
        //加载驱动。
        Class.forName(driver);
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
    try {
        //创建连接。
        conn = DriverManager.getConnection(sourceURL, username, passwd);
        System.out.println("Connection succeed!");
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
    return conn;
}

// 执行普通SQL语句,创建t_user表。
public static void CreateTable(Connection conn) {
    Statement stmt = null;
    try {
        stmt = conn.createStatement();

        //执行普通SQL语句。
        stmt.executeUpdate("DROP TABLE IF EXISTS t_user");
        stmt.executeUpdate("CREATE TABLE t_user(id int, name VARCHAR(20));");
        stmt.close();
    } catch (SQLException e) {
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }
        e.printStackTrace();
    }
}

//执行预处理语句,批量插入数据。
public static void BatchInsertData(Connection conn) {
    PreparedStatement pst = null;

    try {
        //生成预处理语句。
        pst = conn.prepareStatement("INSERT INTO t_user VALUES (?,?)");
        for (int i = 0; i < 20; i++) {
            //添加参数。
            pst.setInt(1, i + 1);
            pst.setString(2, "name " + (i + 1));
            pst.addBatch();
        }
        //执行批处理。
        pst.executeBatch();
        pst.close();
    } catch (SQLException e) {
        if (pst != null) {
            try {
                pst.close();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }
        e.printStackTrace();
    }
}

// 开启流式读,查询t_user表中内容。
public static void StreamingQuery(Connection conn) {
    PreparedStatement pst = null;
    ResultSet resultSet = null;

    try {
        // 查询表t_user中的所有值。
        pst = conn.prepareStatement("SELECT * FROM t_user");
        pst.setFetchSize(Integer.MIN_VALUE);// ((PgStatement)statement).enableStreamingResults(); 两者作用一致。
        resultSet = pst.executeQuery();
        while (resultSet.next()) {
            System.out.println(resultSet.getInt(1));
        }
    } catch (SQLException e) {
        throw new RuntimeException(e);
    } finally {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }

        if (pst != null) {
            try {
                pst.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

public static void main(String[] args) throws Exception {
    String userName = System.getenv("EXAMPLE_USERNAME_ENV");
    String password = System.getenv("EXAMPLE_PASSWORD_ENV");

    Connection conn = getConnection(userName, password);

    CreateTable(conn);

    BatchInsertData(conn);

    StreamingQuery(conn);

    //关闭数据库连接。
    try {
        conn.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

使用流式读功能时,结果集使用完之后,需要执行resultSet.close()或者statement.close()操作,否则当前连接将不可用。