全部产品
Search
文档中心

云原生数据库 PolarDB:JDBC

更新时间:Jun 03, 2026

本文将介绍如何在Java应用中使用JDBC连接PolarDB PostgreSQL版(兼容Oracle)数据库。

适用范围

  • 仅支持PolarDB PostgreSQL版(兼容Oracle) 2.0版本。

  • 已经在PolarDB集群创建用户,如何创建用户请参见创建数据库账号

  • 已经将需要访问PolarDB集群的主机IP地址添加到白名单,如何添加白名单请参见设置集群白名单

背景信息

JDBC(Java Database Connectivity)为Java应用程序提供了访问数据库的编程接口。PolarDB PostgreSQL版(兼容Oracle)数据库的JDBC是基于开源的PostgreSQL JDBC开发而来,使用PostgreSQL本地网络协议进行通信,允许Java程序使用标准的、独立于数据库的Java代码连接数据库。

下载驱动

JDK版本

软件包

1.6

PolarDB-JDBC-42.2.13.0.11.jre6.jar

1.7

PolarDB-JDBC-42.2.13.0.11.jre7.jar

1.8

PolarDB-JDBC-42.5.7.0.14.jre8.jar

说明

由于安全原因,兼容Oracle语法兼容1.0版本的驱动已经下线。如需帮助,联系我们处理

Maven配置

目前PolarDB的JDBC驱动尚未在公开的Maven仓库中提供,当前仅支持通过上传JAR包的方式进行配置。

功能介绍

连接级参数功能

以下功能都通过一个连接参数配置,支持的参数如下表所示。所有的新增参数的生效范围都控制为连接级别,随Connection的生命周期生效。

参数名

说明

autoCommit

开启或关闭参数形式的自动提交。取值如下:

  • true(默认):开启参数形式的自动提交。

  • false:关闭参数形式的自动提交。

autoCommitSpecCompliant

是否允许自动提交下继续调用commit/rollback方法。取值如下:

  • true(默认):允许自动提交下继续调用commit/rollback方法。

  • false:不允许自动提交下继续调用commit/rollback方法。

blobAsBytea

是否支持Oracle兼容的BLOB。取值如下:

  • true(默认):支持Oracle兼容的BLOB。

  • false:不支持Oracle兼容的BLOB。

clobAsText

是否支持Oracle兼容的CLOB。取值如下:

  • true(默认):支持Oracle兼容的CLOB。

  • false:不支持Oracle兼容的CLOB。

collectWarning

是否收集告警(防止内存溢出)。取值如下:

  • true(默认):收集告警。

  • false:不收集告警。

defaultPolarMaxFetchSize

配合MaxFetchSize实现结果集条数控制,默认值为0。

extraFloatDigits

小数长度。

mapDateToTimestamp

是否支持将Date类型转为Timestamp。取值如下:

  • true(默认):支持将Date类型转为Timestamp。

  • false:不支持将Date类型转为Timestamp。

namedParam

是否支持通过:xxx绑定参数。取值如下:

  • true:支持通过:xxx绑定参数。

  • false(默认):不支持通过:xxx绑定参数。

oracleCase

是否返回列名、表名的大写。取值如下:

  • false(默认):不对返回的列名、表名进行转换

  • true返回的列名、表名直接全部转换成大写

  • strict返回的列名、表名在字母全部都是小写的情况下转换成大写

resetNlsFormat

是否在连接初始化时重置nls_date_format/nls_timestamp_format/nls_timestamptz_format为标准格式,以确保日期时间解析一致性

  • false(默认):关闭

  • true:开启

boolAsInt

支持Oracle语义的布尔值表示方式。取值如下:

  • true:布尔值表示为1/0。

  • false(默认):布尔值表示为true/false。

numberStripTrailingZeros

是否对NUMERIC/DECIMAL类型去除尾部零。启用后getString()/getObject()返回值去除小数尾零(如 911.0009113.103.1),行为与Oracle NUMBER一致。

  • false:关闭

  • true(默认):开启

bigintAsNumeric

启用后BIGINT列的getObject()返回BigDecimal而非 Long,便于与Oracle NUMBER行为对齐(如 COUNT(*)结果直接作为BigDecimal使用)。

  • false:关闭

  • true(默认):开启

allowSelectInExecuteUpdate

是否允许executeUpdate()执行 SELECT 语句而不抛异常,返回更新计数为 0。兼容 Oracle 业务中将 SELECT 作为 executeUpdate 调用的场景。

  • false:关闭

  • true(默认):开启

blobUpperHex

是否设置bytea/blob列的getString()返回大写十六进制无前缀格式(如 AABBCC),而非 PostgreSQL 标准的 \xaabbcc 格式,与Oracle RAW输出一致。

  • false:关闭

  • true(默认):开启

unknownLength

未知长度类型的默认返回长度,设为4000以兼容Oracle VARCHAR2 最大长度限制。

  • 可选范围:数字

  • 默认值:4000

数据类型解析

  • Date类型:64位Date类型的支持。

    内核支持了64位的Date,数据表示格式与Oracle相同,带有时分秒信息,对应驱动可以以Timestamp的方式去处理该Date。将所有的Date类型(Types.DATE或者DATEOID)映射成Timestamp类型,驱动将Date视为Timestamp进行处理。

  • Interval类型:支持Oracle模式的Interval输入。

    PG社区的驱动不支持例如+12 12:03:12.111形式的Interval输入,由于目前Oracle模式下该形式是标准输出,所以PolarDB PostgreSQL版(兼容Oracle)支持这种形式的输出。

  • Number类型:支持Number的GET行为。

    Java.sql的标准实现中没有getNumber相关的函数,只有getInt等函数。如果一个函数的参数类型是Number,允许使用getInt、setInt、RegisterParam等接口将参数以Int形式传递。

  • Blob类型:Blob处理为Bytea,Clob处理为Text。

    针对Java.sql.Blob和Java.sql.Clob接口的实现。内核已经为Blob、Clob添加了映射,在Java层面也可以按照Bytea、Text的方式去处理。主类实现了getBytes、setBytes、position、getBinaryStream等方法。

  • Boolean类型:支持布尔类型转义为1/0。

    为了保证老版本的兼容性,setBoolean 接口方法在设置时默认采用 true/false。然而,用户可以通过激活 boolAsInt 参数来切换至与Oracle兼容的1/0语义,以此适应Oracle兼容的数据库交互需求。

    说明

    针对数字类型转换为Boolean类型,不同版本的驱动包处理规则存在差异,具体区别如下:

    • 42.5.4.0.10及以下版本:1或等同于1的数字视为True,0或等同于0的数字视为False,其他数字值则返回错误。

    • 42.5.4.0.11及以上版本:0或等同于0的数字视为False,其他非0的数字值均视为True,此版本驱动的这一行为与Oracle驱动保持一致。

PL/SQL适配

  • 支持不带$$符号的存储过程。

    支持在创建FUNCTION/PROCEDURE等过程时省略$$符号,并支持在语法解析时截断/字符。

  • 支持冒号变量名作为参数。

    支持使用:xxx这种方式传递参数,其中xxx为冒号开头的变量名。

  • 支持匿名块绑定参数。

  • 支持屏蔽PLSQL的警告信息。

    防止循环中存储过多的警告信息导致内存超限。

Oracle q-quote字面量语法

自42.5.7.0.14版本起,驱动完整支持Oracle q-quote语法的所有合法 delimiter(包括 ' 作 delimiter 的 q''..'' 特殊形态)。在PreparedStatement中q-quote内部的?:xxx不会被误判为绑定参数:

-- 标准 q-quote:使用 [ ] 作为定界符
SELECT q'[It's a test]' FROM dual;
-- 结果: It's a test

-- 单引号作 delimiter 的特殊形态
SELECT q''te:s't ? :44'' FROM dual;
-- 结果: te:s't ? :44
// q-quote 内的 ? 和 :param 不会被识别为绑定参数
PreparedStatement ps = conn.prepareStatement(
    "SELECT q'[where id = ? and name = :test]' FROM dual");
ResultSet rs = ps.executeQuery();
rs.next();
System.out.println(rs.getString(1));
// 输出: where id = ? and name = :test

TABLE OF / INDEX BY 集合类型

自42.5.7.0.14版本起,驱动支持通过CallableStatement接收 PolarDB 的 TABLE OF / INDEX BY 集合类型作为 OUT 参数。使用 Types.ARRAY 注册 OUT 参数,通过 getArray() 获取 PgArray 对象,其中保留了关联数组的 key 信息。

典型用法:

// 假设数据库中有如下类型和函数:
// CREATE TYPE str_table IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;
// CREATE FUNCTION get_names() RETURN str_table IS ...

CallableStatement cs = conn.prepareCall("{ ? = call get_names() }");
cs.registerOutParameter(1, Types.ARRAY);
cs.execute();

// 方式一:直接获取 Array 的 Java 数组
Array arr = cs.getArray(1);

String[ ] values = (String[ ]) arr.getArray();

// values = ["alpha", "beta", "gamma"]

// 方式二:通过 ResultSet 遍历,并获取关联数组的 key
ResultSet rs = arr.getResultSet();
while (rs.next()) {
    int key = rs.getInt(1);      // 关联数组的 key(如 1, 2, 3)
    String val = rs.getString(2); // 对应的值
    System.out.println(key + " => " + val);
}
cs.close();

数值类型 OUT 参数自动转换

自42.5.7.0.14版本起,CallableStatement 的 OUT 参数支持全数值族类型自动互转。即使数据库函数返回 BIGINT,用户注册为 Types.NUMERIC 也能正确获取值,反之亦然。支持的类型包括:SMALLINT、INTEGER、BIGINT、NUMERIC、DECIMAL、REAL、FLOAT、DOUBLE。

典型用法(适用于 DBMS_SQL.EXECUTE 等返回 BIGINT 的场景):

// 数据库函数实际返回 BIGINT,但业务框架按 Oracle 惯例注册为 NUMERIC
CallableStatement cs = conn.prepareCall("{ ? = call dbms_sql.execute(?) }");
cs.registerOutParameter(1, Types.NUMERIC);  // 注册为 NUMERIC
cs.setInt(2, cursorId);
cs.execute();

// 驱动自动完成 BIGINT → NUMERIC 转换
BigDecimal result = cs.getBigDecimal(1);
System.out.println(result); // 正常获取值,无类型不匹配错误
cs.close();

示例

加载JDBC驱动

在应用中执行以下命令加载JDBC驱动:

Class.forName("com.aliyun.polardb2.Driver");
说明

如果是通过项目导入的方式导入JDBC,以上驱动都会自动注册完成,不需要额外注册。

连接数据库

jdbc:polardb协议

在JDBC中,一个数据库通常用一个URL来表示,示例如下:

jdbc:polardb://pc-***.o.polardb.rds.aliyuncs.com:1521/polardb_test?user=test&password=Pw123456

参数

示例

说明

URL前缀

jdbc:polardb://

连接PolarDB的URL,使用jdbc:polardb://作为前缀。

连接地址

pc-***.o.polardb.rds.aliyuncs.com

PolarDB集群的连接地址,如何查看连接地址请参见查看或申请连接地址

端口

1521

PolarDB集群的端口,默认为1521。

数据库

polardb_test

需要连接的数据库名。

用户名

test

PolarDB集群的用户名。

密码

Pw123456

PolarDB集群用户名对应的密码。

jdbc:postgresql协议

支持使用jdbc:postgresql://协议连接集群。然而,为避免与原生PostgreSQL驱动产生冲突而导致其他连接异常,需在连接字符串末尾添加forceDriverType=true参数以显式启用。使用示例如下:

jdbc:postgresql://pc-***.o.polardb.rds.aliyuncs.com:1521/postgres?forceDriverType=True

参数

示例

说明

URL前缀

jdbc:postgresql://

连接PolarDB的URL,使用jdbc:postgresql://作为前缀。

连接地址

pc-***.o.polardb.rds.aliyuncs.com

PolarDB集群的连接地址,如何查看连接地址请参见查看或申请连接地址

端口

1521

PolarDB集群的端口,默认为1521。

查询并处理结果

访问数据库执行查询时,需要创建一个StatementPreparedStatment或者CallableStatement对象。

PreparedStatment示例如下:

PreparedStatement st = conn.prepareStatement("select id, name from foo where id > ?");
st.setInt(1, 10);
resultSet = st.executeQuery();
while (resultSet.next()) {
    System.out.println("id:" + resultSet.getInt(1));
    System.out.println("name:" + resultSet.getString(2));
}

调用函数/存储过程

您可使用JDBC的CallableStatement对象调用函数(Function)和存储过程(Procedure)。

说明

PolarDB PostgreSQL版(兼容Oracle)升级CALL函数的语法逻辑,支持更加丰富的JDBC绑定参数用法。使用前,请确保您使用的是最新版的JDBC驱动包。

参数说明

参数类型

JDBC注册方式

Java设置方式

Java获取方式

IN

无需注册

setXXX(index, value)

不可获取

IN OUT

registerOutParameter(index, type)

setXXX(index, value)

getXXX(index)

OUT

registerOutParameter(index, type)

无需设置

getXXX(index)

存储过程调用示例

集群中创建一个test_in_out_procedure存储过程。

CREATE OR REPLACE PROCEDURE test_in_out_procedure (a IN number, b IN OUT number, c OUT number) IS
BEGIN
    b := a + b;
    c := b + 1;
END;

Java中创建一个CallableStatement对象,用于调用test_in_out_procedure存储过程。

CallableStatement cstmt = connection.prepareCall("{call test_in_out_procedure(?, ?, ?)}");

// IN 参数 a
cstmt.setInt(1, 1);

// IN OUT 参数 b
cstmt.setInt(2, 2);
cstmt.registerOutParameter(2, Types.INTEGER);

// OUT 参数 c
cstmt.registerOutParameter(3, Types.INTEGER);

cstmt.execute();

int b = cstmt.getInt(2);
int c = cstmt.getInt(3);

函数调用示例

集群中创建一个test_in_out_function函数。

CREATE OR REPLACE FUNCTION test_in_out_function (a IN number, b IN OUT number, c OUT number) RETURN number AS
BEGIN
    b := a + b;
    c := b + 1;
    RETURN c + 1;
END;

在Java中支持两种调用方式。

  • 使用JDBC转义语法 (Escape Syntax):

    CallableStatement cstmt = connection.prepareCall("{?= call test_in_out_function(?, ?, ?)}");
    
    // 返回值 r
    cstmt.registerOutParameter(1, Types.INTEGER);
    
    // IN 参数 a
    cstmt.setInt(2, 1);
    
    // IN OUT 参数 b
    cstmt.setInt(3, 2);
    cstmt.registerOutParameter(3, Types.INTEGER);
    
    // OUT 参数 c
    cstmt.registerOutParameter(4, Types.INTEGER);
    
    cstmt.execute();
    
    int r = cstmt.getInt(1);
    int b = cstmt.getInt(3);
    int c = cstmt.getInt(4);
  • 使用BEGIN ... END;匿名块包装:

    CallableStatement cstmt = connection.prepareCall("BEGIN ? := test_in_out_function(?, ?, ?); END;");
    
    // 返回值 r
    cstmt.registerOutParameter(1, Types.INTEGER);
    
    // IN 参数 a
    cstmt.setInt(2, 1);
    
    // IN OUT 参数 b
    cstmt.setInt(3, 2);
    cstmt.registerOutParameter(3, Types.INTEGER);
    
    // OUT 参数 c
    cstmt.registerOutParameter(4, Types.INTEGER);
    
    cstmt.execute();

函数作为存储过程调用

集群中创建一个test_in_out_function_as_procedure_1存储过程。其中,直接调用test_in_out_function函数并给OUT参数赋值。

CREATE OR REPLACE PROCEDURE test_in_out_function_as_procedure_1 (
    a IN number,
    b IN OUT number,
    c OUT number,
    r OUT number
) AS
BEGIN
    r := test_in_out_function(a, b, c);
END;
CallableStatement cstmt = connection.prepareCall("{call test_in_out_function_as_procedure_1(?, ?, ?, ?)}");

cstmt.setInt(1, 1); // a
cstmt.setInt(2, 2); // b
cstmt.registerOutParameter(2, Types.INTEGER);
cstmt.registerOutParameter(3, Types.INTEGER); // c
cstmt.registerOutParameter(4, Types.INTEGER); // r

cstmt.execute();

int b = cstmt.getInt(2);
int c = cstmt.getInt(3);
int r = cstmt.getInt(4);

函数通过SELECT INTO调用

集群中创建一个test_in_out_function_as_procedure_2存储过程。其中,test_in_out_function函数通过SELECT INTO调用。

CREATE OR REPLACE PROCEDURE test_in_out_function_as_procedure_2 (
    a IN number,
    b IN OUT number,
    c OUT number,
    r OUT number
) AS
BEGIN
    SELECT test_in_out_function(a, b, c) INTO r FROM dual;
END;
CallableStatement cstmt = connection.prepareCall("{call test_in_out_function_as_procedure_2(?, ?, ?, ?)}");

cstmt.setInt(1, 1); // a
cstmt.setInt(2, 2); // b
cstmt.registerOutParameter(2, Types.INTEGER);
cstmt.registerOutParameter(3, Types.INTEGER); // c
cstmt.registerOutParameter(4, Types.INTEGER); // r

cstmt.execute();

使用结构体(Struct)作为参数

42.5.4.0.12(2025-08-13)版本后,数据库驱动支持createStruct语法,您可使用Struct结构体作为函数的入参。这使得在Java代码中构建并传递数据库自定义的复合类型(或对象类型)变得非常方便。

// 假设 conn 是一个已建立的数据库连接对象
public void testSelectBoolean1() throws Exception {
  // 1. 准备构成结构体的属性数组。
  // 数组元素的顺序和类型必须与数据库中定义的 test_object 类型严格匹配。
  Object[] addressAttributes = new Object[] {
      Integer.valueOf(42),                     // Integer
      new BigDecimal("9999.99"),               // java.math.BigDecimal
      Boolean.TRUE,                            // Boolean
      new Date(),                              // java.util.Date
      new Timestamp(System.currentTimeMillis()), // java.sql.Timestamp
      "这是一个测试字符串",                      // String
      new StringBuilder("可变字符串"),           // StringBuilder
      null,                                    // null
  };
  
  // 2. 使用 conn.createStruct 创建 Struct 对象
  Struct addressStruct = conn.createStruct("test_object", addressAttributes);
  
   // 3. 准备并执行 CallableStatement 来调用函数
  CallableStatement stmt = conn.prepareCall("{? = call test_object_func(?)}");
  stmt.registerOutParameter(1, Types.VARCHAR);
  stmt.setObject(2, addressStruct);
  stmt.execute();
  
  // 4. 获取并打印函数返回值
  System.out.println(stmt.getObject(1).toString());
  
  stmt.close();
}

相关工具适配

适配Hibernate

  • hibernate.cfg.xml驱动类与方言配置:如果您的工程使用Hibernate连接数据库,请在您的Hibernate配置文件hibernate.cfg.xml中配置PolarDB数据库的驱动类和方言。

    说明

    Hibernate需要为3.6及以上版本才支持PostgresPlusDialect方言。

    <property name="connection.driver_class">com.aliyun.polardb2.Driver</property>
    <property name="connection.url">jdbc:polardb://pc-***.o.polardb.rds.aliyuncs.com:1521/polardb_test</property>
    <property name="dialect">org.hibernate.dialect.PostgresPlusDialect</property>
  • DATE类型配置:对于表中DATE类型的列,需要在Hibernate的.hbm.xml文件中调整配置type="java.util.Date"以确保Hibernate读写PolarDBDATE类型数据时保留时分秒精度。如果直接使用type="date",则可能造成DATE精度丢失。示例配置如下:

    <!-- 其他配置信息 -->
    <hibernate-mapping package="com.aliyun.polardb2.demo">
        <class name="TestTableEntity" table="test_table_name">
            <!-- 其他列信息 -->
            <property name="currentDate" column="curr_date" type="java.util.Date"/> <!-- 指定java.util.Date类型以保留date精度 -->
            <!-- 其他列信息 -->
        </class>
    </hibernate-mapping>
  • LOB(Large Objects)大对象类型配置:原生PostgreSQL不支持LOB类型,因此PostgresPlusDialect方言将CLOB、BLOB类型的列都映射为oid类型的列,这会导致插入该列的字符串被转为oid数字。PolarDB PostgreSQL版Oracle语法兼容 2.0将CLOB类型映射为text类型,BLOB映射为bytea类型。需要指定列的类型使之生效,以下配置二选一即可。

    • 配置一:Java类定义。

      @Lob
      @Column(name = "col_clob")
      @Type(type = "text")
      private String columnClob;
      
      @Lob
      @Column(name = "col_blob")
      @Type(type = "bytea")
      private String columnBlob;
    • 配置二:在Hibernate的.hbm.xml文件定义。

      <!-- 其他配置信息 -->
      <hibernate-mapping package="com.aliyun.polardb2.demo">
          <class name="TestTableEntity" table="test_table_name">
              <!-- 其他列信息 -->
              <property name="columnClob" column="col_clob" type="text"/>
              <property name="columnBlob" column="col_blob" type="bytea"/>
              <!-- 其他列信息 -->
          </class>
      </hibernate-mapping>

Druid连接池

Druid是一个数据库连接池,您可以通过它来管理应用程序与PolarDB PostgreSQL版(兼容Oracle)之间的连接。当您使用Druid连接时,为确保功能的完整性和稳定性,请注意以下关键配置:

  1. Druid是从1.2.26版本开始支持PolarDB的,请确保您项目中引用的版本不低于此版本。以Maven为例:

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.26</version>
    </dependency>
  2. 在初始化连接池时,必须显式设置驱动类名(driverClassName)和数据库类型(dbType)。

    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName("com.aliyun.polardb2.Driver");
    dataSource.setDbType("polardb2");
  3. 使用SQL防火墙(WallFilter)严格检查业务SQL是否符合Oracle语法规范,防止SQL注入风险。

    // 1. 配置 WallConfig
    WallConfig wallConfig = new WallConfig();
    
    // 1.1 是否进行严格的语法检查,必填
    wallConfig.setStrictSyntaxCheck(true);
    
    // 1.2 更精细的语法控制,仅列举部分,可选
    wallConfig.setMultiStatementAllow(false);    // 是否允许一次执行多条语句
    wallConfig.setCommentAllow(true);            // 允许注释
    wallConfig.setSelectIntoAllow(true);         // 允许SELECT INTO
    wallConfig.setDeleteWhereNoneCheck(true);    // 检查DELETE语句是否无条件
    
    // 2. 使用 WallConfig 配置 WallFilter
    WallFilter wallFilter = new WallFilter();
    wallFilter.setConfig(wallConfig);
    
    // 3. 使用 WallFilter 配置连接池
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.getProxyFilters().add(wallFilter);
  4. 如果需要在Druid连接池中对数据库密码进行加密,请参见数据库密码加密

适配WebSphere

使用WebSphere时,配置PolarDB的JDBC作为数据源,步骤如下所示:

  1. 数据库类型选择用户自定义的

  2. 实现类名为:com.aliyun.polardb2.ds.PGConnectionPoolDataSource

  3. 类路径选择JDBC jar包所在路径。

适配Spring框架

在Spring框架中使用新版本JDBC(版本号≥ 42.5.4.0.11)时,可以直接将结构体类型(Struct)作为存储过程参数传入,无需额外的代码改造。以下示例演示了如何通过GetUserProcedure方法调用存储过程get_user_info,其中参数c为复合类型com,通过构建相应的结构体对象实现复合类型的参数传递。

public class GetUserProcedure extends StoredProcedure {
    private static final String PROCEDURE_NAME = "get_user_info";

    public GetUserProcedure(DataSource dataSource) {
        super(dataSource, PROCEDURE_NAME);
        init();
    }

    private void init() {
        // 声明输入参数
        declareParameter(new SqlParameter("p_user_id", Types.NUMERIC));
        declareParameter(new SqlParameter("c", Types.STRUCT, "com"));

        compile(); // 必须调用 compile()
    }

    public Map<String, Object> getUserInfo(Integer userId) {
        Map<String, Object> inputs = new HashMap<>();
        inputs.put("p_user_id", userId);
        Calendar cal = Calendar.getInstance();
        cal.set(2023, Calendar.OCTOBER, 1, 12, 30, 45); // 注意:Calendar 的月份从 0 开始
        cal.set(Calendar.MILLISECOND, 0);

        Rec rec = new Rec();
        rec.t1 = 1;
        rec.t2 = "some text";
        rec.t3 = new Date(cal.getTime().getTime());
        rec.t4 = true;
        rec.t5 = null;
        inputs.put("c", rec);

        return execute(inputs); // 执行存储过程
    }
}

适配Apache ShardingSphere

您可以通过Apache ShardingSphere连接并管理PolarDB PostgreSQL版(兼容Oracle)集群,以实现数据分片、读写分离等高级功能。由于PolarDB完全兼容PostgreSQL协议,而ShardingSphere原生支持该协议,因此两者可以无缝集成。

注意事项

配置时,请遵循以下关键步骤,确保ShardingSphere能正确识别并使用PolarDB的JDBC驱动。

  • ShardingSphere配置:在ShardingSphere的数据源配置中,需将驱动类名(driverClassName)设置为 com.aliyun.polardb2.Driver

  • 驱动版本:需为42.5.4.0.12(2025-08-13)及以上版本。

  • 连接协议:需使用jdbc:postgresql协议,且需在连接字符串末尾添加forceDriverType=true参数。

连接示例

以下是一个在ShardingSphere中配置PolarDB数据源的YAML示例(config-sharding.yaml):

dataSources:
  ds0:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.aliyun.polardb2.Driver
    jdbcUrl: jdbc:postgresql://pc-***.o.polardb.rds.aliyuncs.com:1521/postgres?forceDriverType=True
    username: ******
    password: ******
    maxPoolSize: 2
    minPoolSize: 2
  ds1:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.aliyun.polardb2.Driver
    jdbcUrl: jdbc:postgresql://pc-***.o.polardb.rds.aliyuncs.com:1521/postgres?forceDriverType=True
    username: ******
    password: ******
    maxPoolSize: 2
    minPoolSize: 2

常见问题

如何选择JDBC驱动,是否可以使用开源社区驱动?

PolarDB PostgreSQL版(兼容Oracle)兼容版在开源PostgreSQL的基础上实现了众多兼容性相关的特性,有些特性需要驱动层配合实现,因此,推荐使用PolarDB的JDBC驱动。相关驱动可以在官网驱动下载页面下载。

公共Maven仓库是否有PolarDB JDBC驱动?

按照官网描述,JDBC驱动需要在官网下载jar包,对于Maven工程需要手动安装该jar包至本地仓库使用,目前仅支持官网下载JDBC驱动包一种方式。

如何查看版本号?

通过运行java -jar 驱动名来查看版本号。

是否支持在URL中配置多个IP和端口?

PolarDB PostgreSQL版(兼容Oracle)的JDBC驱动支持在URL中配置多个IP和端口,示例如下:

jdbc:polardb://1.2.XX.XX:5432,2.3.XX.XX:5432/postgres
说明

配置多个IP后,创建连接时会依次尝试通过这些IP创建连接,若都不能创建连接,则连接创建失败。每个IP尝试创建连接的超时时间默认为10s,即connectTimeout,若要修改超时时间,可在连接串中添加该参数进行设置。

游标类型如何选择?

如果是java 1.8之前的JDK,使用Types.REF;如果是java 1.8及其之后的版本,可以使用Types.REF_CURSOR。

是否支持默认返回大写的列名?

可以在JDBC连接串中添加参数oracleCase=true,该参数会将返回的列名默认转换为大写,示例如下:

jdbc:polardb://1.2.XX.XX:5432,2.3.XX.XX:5432/postgres?oracleCase=true

版本更新日志

42.5.7.0.14 (2026-05-28)

新增功能

  • Oracle 特有语法与 PL/SQL 深度兼容

    • 全面支持 Oracle q-quote 字面量:支持所有合法的分隔符(包括 []{}<>() 及任意单字符),并特别支持以单引号 ' 作为分隔符的 q''..'' 格式。在 PreparedStatement 预编译执行时,q-quote 内部的 ? 或 :xxx 占位符不会再被误判为绑定参数。

    • 支持 TABLE OF / INDEX BY 集合类型:完整支持 PolarDB 关联数组(PL/SQL INDEX BY),包含跨包引用的 TABLE OF RECORD 复杂类型。CallableStatement 可直接通过 registerOutParameter(idx, Types.ARRAY) 接收关联数组返回值,且 getArray() 返回的 PgArray 对象将完整保留原始 Key 信息。

    • 支持 DO 匿名块与 N INOUT 参数:允许在 DO $ ... $$ 匿名块中绑定 $1$2 等位置参数,并支持使用 INOUT 模式传递参数。

    • 支持 Oracle 风格序列伪列:支持在 SQL 中直接调用并解析 sequence.NEXTVAL 和 sequence.CURRVAL 伪列。

    • 自定义类型名解析:registerOutParameter(idx, type, typeName) 支持传入类型名称,以实现对自定义 TABLE OF 或 RECORD 类型的精准解析。

    • 复合类型数组与 Struct 解析:支持通过 createArrayOf 创建复合类型数组,并支持对 Struct 类型数组元素进行序列化(包含跨包的 TABLE OF RECORD 类型)。

  • 数据类型映射与输出规范对齐

    • 数值类型 OUT 参数全族自动互转:重构了 CallableStatement 的输出参数类型转换机制。采用 toNumeric + fromNumeric 双阶段归一化策略,完美实现 SMALLINTINTEGERBIGINTNUMERICDECIMALREALFLOATDOUBLE 之间的双向自动转换。彻底解决如 DBMS_SQL.EXECUTE 返回 BIGINT 但框架注册为 NUMERIC 时,报 Types=-5 vs Types=2 类型不匹配的兼容性报错。

    • 自动去除 NUMBER 尾部多余零:新增连接参数 numberStripTrailingZeros(默认值为 true)。当调用 getString() 或 getObject() 获取 NUMERICDECIMALBIGINT 类型的值时,驱动将自动去除尾部的无效零(例如将 911.000 转化为 911),使输出行为与 Oracle NUMBER 保持一致,解决 Spring queryForList() 等场景下 BigDecimal 尾零未去除的问题。

    • 支持 BIGINT 映射为 BigDecimal:新增连接参数 bigintAsNumeric(默认值为 true)。开启后,BIGINT 列在执行 getObject() 时将返回 BigDecimal 而非 Long,对齐 Oracle NUMBER 的默认行为。

    • BLOB 十六进制大写输出:新增连接参数 blobUpperHex(默认值为 true)。bytea/blob 列通过 getString() 获取时,将返回无前缀的大写十六进制格式(如 AABBCC),与 Oracle RAW 类型的输出行为保持一致。

    • 支持 TEXT 列返回 Clob:当配置连接参数 clobAsText=true 时,TEXT 类型列执行 getObject() 将返回 java.sql.Clob 对象,无缝兼容基于 Oracle CLOB 接口开发的应用。

    • 支持 Oracle NLS 日期格式:支持在 Oracle NLS_DATE_FORMAT 参数配置下进行日期字符串解析,兼容 RR 格式的两位年份转换(例如将 01-JAN-25 正确转换为 2025 年)。

  • 历史代码习惯兼容

    • 支持 executeUpdate 执行 SELECT 语句:新增连接参数 allowSelectInExecuteUpdate(默认值为 true)。允许通过 executeUpdate() 执行 SELECT 查询且不抛出任何异常,最大程度兼容 Oracle 业务代码中的历史开发习惯。

参数默认值变更

  • resetNlsFormat 默认值由 true 调整为 false:驱动在建立连接时不再强制重置 NLS 日期格式,而是尊重服务端的既有配置,避免在数据库审计日志中产生非预期的 SET 语句。

  • unknownLength 默认值由 Integer.MAX_VALUE 调整为 4000:对齐 Oracle VARCHAR2(4000) 的最大长度限制,彻底解决部分应用框架在读取 columnSize 元数据时发生异常的问题。

缺陷修复

  • PL/SQL 与集合类型解析修复

    • 修复了 q-quote 解析中单引号作为分隔符时失败的问题(此前 q''te:s't ? :44'' 场景会抛出 Unterminated string literal 错误,现已能正确识别 '' 作为结束标记)。

    • 修复了 TABLE OF 数组外层括号解析错误的问题。解决因 PolarDB 服务端返回带圆括号的字符串(如 (1 => "alpha", ...)),导致解析结果中第一个 key 多出左括号 (、最后一个 value 多出右括号 ) 的缺陷。

    • 修复了 CallableStatement.executeQuery() 在存储过程无结果集返回时输出 null 的问题。现改为返回空的 ResultSet,避免引发 HikariCP 等连接池包装层报空指针异常(NPE)。

    • 修复了 Oracle 模式下集合类型参数的 OID(对象标识符)解析异常,解决了存储过程集合类型出参转换失败的问题。

    • 修复了执行 DO 匿名块时,由于 resultFields 为空(null)导致系统崩溃并抛出空指针异常(NPE)的缺陷。

    • 修复了未显式注册的 INOUT 参数产生多余输出列时,导致驱动运行崩溃的问题,现已加入多余返回列的容错处理。

  • 数据类型、格式转换与序列化修复

    • 统一了 Timestamp.getString() 在所有业务场景下的时间戳字符串输出格式。

    • 修复了复合类型序列化中的以下多项兼容性缺陷:

      • 当 Struct 字段中含有括号或逗号时未添加双引号包裹,导致服务端报 malformed record literal 语法错误的问题;

      • PGobject 数组元素缺失外层括号,且单字段 PGobject 值未自动包裹的问题;

      • 复合类型数组编码错误的缺陷;

      • 复合类型中 null 日期字段编码异常的问题;

      • 复合记录字面量(Composite Record Literal)内部字段包含括号时,转义解析错误的缺陷。

    • 修复了将 LocalDateTime 传入 setObject(localDateTime, Types.DATE) 时触发的类型转换异常。

    • 修复了在开启 bigintAsNumeric=true 且处于服务端预编译(Server-side prepare)模式下,导致 JVM 栈递归调用溢出的缺陷。

    • 修复了 CallableStatement 中日期/时间类型 OUT 参数在特定上下文下的转换错误。

    • 修复了在设置 clobAsText=true 时,TEXT 类型列未能正确返回 Clob 对象的缺陷。

  • 元数据与环境配置修复

    • 修复了元数据中 VARCHAR 列的大小限制(固定为 4000),并修正了字符和 LOB 列的大小限制逻辑,与 Oracle 元数据行为保持一致。

    • 修复了 Oracle 兼容模式下 DATE 列的类型名称显示问题,确保调用 getColumnTypeName() 时能正确返回对应的类型名称。

    • 取消了在建立连接时将 DateStyle 强制设置为 ISO 的逻辑,转为尊重服务端的参数配置。

    • 统一了错误码转换规范:将数据库服务端返回的负数错误码转换为正数,以完美对齐 Oracle 的 SQLCODE 错误码规范。

    • 修复了 SQL 语句解析器中的正则表达式逻辑错误,提升了对各类 SQL 语句类型判断的准确性。

    • 修复了执行函数调用时,因参数数组大小及数量校验逻辑不严谨导致的调用失败缺陷。

工程优化

  • 重构 PgConnection 核心类:深度优化内部代码结构,显著提升驱动在复杂连接管理下的执行效率与可维护性。

  • 引入原始类型 OID 跟踪机制:在调试模式下支持对复杂类型映射关系进行全程追踪,极大便利了开发人员定位底层类型转换与 OID 异常问题。

  • 升级 forbiddenapis 插件版本至 3.10:加强了编译期的 API 禁用检查,规避潜在的平台相关性及不安全 API 调用风险。

42.5.7.0.13 (2025-12-24)

  • 核心组件升级:将JDBC驱动版本同步至社区42.5.x系列的最新稳定版(42.5.7),引入了最新的安全补丁与性能优化。

  • 连接稳定性增强:深度修复了在特定连接池场景下可能出现的连接泄漏隐患,提升了长连接环境下的资源管理可靠性。

  • 第三方生态兼容性优化:确保第三方框架(如MyBatis、Hibernate等)能够准确识别驱动类型,避免因识别偏差导致的兼容性异常。

    • 调整getDatabaseProductName返回值为PostgreSQL

    • 调整DRIVER_NAME返回值为PolarDB-2.0 JDBC Driver

  • 驱动冲突规避:移除了对jdbc:oracle:thin:连接协议的支持。此举旨在消除在多驱动并存的项目中与原生Oracle驱动的潜在冲突,确保驱动加载逻辑的唯一性与准确性。

  • Oracle迁移适配增强:优化了getTables接口的检索逻辑,支持通过大写表名查找表。该特性适配了从Oracle迁移至PolarDB的Java业务代码逻辑,降低了应用迁移的改造成本。

42.5.4.0.12(2025-08-13)

42.5.4.0.10.11(2025-07-10)

42.5.4.0.10.9(2025-03-19)

  • 支持Oracle风格的函数绑定参数功能。

  • 修复一个END会导致解析失败的缺陷。

42.5.4.0.10.7(2025-01-06)

  • 支持兼容Oracle方式的注释功能(即支持/* /* Comments */功能)。

  • 修复Mybatis调用Clob接口时,使用空值导致的Misuse of castNonNull问题。

42.5.4.0.10.6(2024-12-04)

  • 支持高版本JDBC的Channel Binding功能。

  • 升级escapeSyntaxCallMode参数默认值为callIfNoReturn,适配Oracle的参数绑定行为。

  • 修复attidentity识别错误可能导致的列类型获取不正确缺陷。

42.5.4.0.10.5(2024-10-24)

  • 优化resetNlsFormat参数的设置,确保连接时的正确配置。同时,避免在审计日志中留下非预期的执行记录。

  • 修复逻辑复制测试中因无法识别java.nio.Buffer类型接口而导致的错误。

  • 修复存储过程中CASE WHEN...END识别结束解析不正确的问题。

42.5.4.0.10.4(2024-09-02)

  • 修复了PL块中绑定不正确的问题。针对此问题对性能的影响,默认已关闭该功能。

  • 支持在同一类型内部进行隐式转换,允许字符类型(如VARCHARCHAR)和数字类型(如NUMERICINTEGERDOUBLE)作为INOUT参数相互转换。

  • 驱动中元信息的 getDatabaseProductName()函数返回值现为:“POLARDB2 Database Compatible with Oracle”。

42.5.4.0.10.2(2024-07-19)

  • 修复了在Mybatis中,当对象实体注册类型为Timestamp时,数据库无法正确推断参数类型的问题。