All Products
Search
Document Center

PolarDB:JDBC

Last Updated:Mar 28, 2026

Connect a Java application to PolarDB for PostgreSQL (Compatible with Oracle) using the PolarDB JDBC driver, which is built on the open source PostgreSQL JDBC driver and uses the native PostgreSQL network protocol.

Prerequisites

Before you begin, make sure that you have:

  • A PolarDB for PostgreSQL (Compatible with Oracle) cluster running Version 2.0

  • A database account created in the cluster. For more information, see Create a database account.

  • The IP address of your host added to the cluster whitelist. For more information, see Set a cluster whitelist.

Download the driver

Download the JAR package that matches your JDK version:

JDK versionPackage
1.6PolarDB-JDBC-42.2.13.0.11.jre6.jar
1.7PolarDB-JDBC-42.2.13.0.11.jre7.jar
1.8PolarDB-JDBC-42.5.7.0.13.jre8.jar
The driver for Oracle syntax-compatible Version 1.0 has been removed for security reasons. If you need assistance, contact us.

Add the driver to your project

The PolarDB JDBC driver is not yet available in public Maven repositories. You must configure it by manually uploading the JAR package.

Connect to the database

Load the driver

Load the PolarDB JDBC driver class:

Class.forName("com.aliyun.polardb2.Driver");
If you import the driver through a project dependency, it registers automatically. You do not need to call Class.forName again.

Connection URL formats

jdbc:polardb protocol

jdbc:polardb://pc-***.o.polardb.rds.aliyuncs.com:1521/polardb_test?user=test&password=Pw123456
ParameterExampleDescription
URL prefixjdbc:polardb://The URL prefix for PolarDB connections.
Endpointpc-***.o.polardb.rds.aliyuncs.comThe cluster endpoint. For more information, see View or request an endpoint.
Port1521The default port for PolarDB clusters.
Databasepolardb_testThe name of the database to connect to.
UsernametestThe database account username.
PasswordPw123456The password for the database account.

jdbc:postgresql protocol

If your project already uses a native PostgreSQL JDBC driver, use the jdbc:postgresql:// prefix and add forceDriverType=true to ensure the PolarDB driver handles the connection.

jdbc:postgresql://pc-***.o.polardb.rds.aliyuncs.com:1521/postgres?forceDriverType=True
ParameterExampleDescription
URL prefixjdbc:postgresql://The URL prefix.
Endpointpc-***.o.polardb.rds.aliyuncs.comThe cluster endpoint. For more information, see View or request an endpoint.
Port1521The default port for PolarDB clusters.

Quick start example

The following example shows a complete, runnable connection and query. Store credentials in environment variables rather than hardcoding them in your application.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;

public class PolarDBQuickStart {
    public static void main(String[] args) throws Exception {
        Class.forName("com.aliyun.polardb2.Driver");

        // Read credentials from environment variables to avoid hardcoding sensitive values.
        String user = System.getenv("POLARDB_USER");
        String password = System.getenv("POLARDB_PASSWORD");
        String url = "jdbc:polardb://pc-***.o.polardb.rds.aliyuncs.com:1521/polardb_test";

        Properties props = new Properties();
        props.setProperty("user", user);
        props.setProperty("password", password);

        try (Connection conn = DriverManager.getConnection(url, props)) {
            System.out.println("Connected to PolarDB successfully.");

            PreparedStatement st = conn.prepareStatement(
                "SELECT id, name FROM foo WHERE id > ?"
            );
            st.setInt(1, 10);

            try (ResultSet rs = st.executeQuery()) {
                while (rs.next()) {
                    System.out.println("id: " + rs.getInt(1));
                    System.out.println("name: " + rs.getString(2));
                }
            }
        }
    }
}
Tip: Pass connection parameters using a Properties object rather than inlining credentials in the URL. This keeps sensitive values out of connection strings and makes it easier to manage configuration separately from code.

Call functions and stored procedures

Use the CallableStatement interface to call functions and stored procedures.

PolarDB for PostgreSQL (Compatible with Oracle) has upgraded the CALL syntax to support a wider range of JDBC parameter binding methods. Make sure you are using the latest version of the driver.

Parameter types

Parameter typeRegisterSetRetrieve
INNot requiredsetXXX(index, value)Not retrievable
IN OUTregisterOutParameter(index, type)setXXX(index, value)getXXX(index)
OUTregisterOutParameter(index, type)Not requiredgetXXX(index)

Call a stored procedure

Create the test_in_out_procedure stored procedure in your cluster:

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;

Call it from Java:

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

// IN parameter a
cstmt.setInt(1, 1);

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

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

cstmt.execute();

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

Call a function

Create the test_in_out_function function in your cluster:

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;

Two calling styles are supported:

JDBC escape syntax:

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

// Return value r
cstmt.registerOutParameter(1, Types.INTEGER);

// IN parameter a
cstmt.setInt(2, 1);

// IN OUT parameter b
cstmt.setInt(3, 2);
cstmt.registerOutParameter(3, Types.INTEGER);

// OUT parameter c
cstmt.registerOutParameter(4, Types.INTEGER);

cstmt.execute();

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

Anonymous block wrapper:

CallableStatement cstmt = connection.prepareCall("BEGIN ? := test_in_out_function(?, ?, ?); END;");

// Return value r
cstmt.registerOutParameter(1, Types.INTEGER);

// IN parameter a
cstmt.setInt(2, 1);

// IN OUT parameter b
cstmt.setInt(3, 2);
cstmt.registerOutParameter(3, Types.INTEGER);

// OUT parameter c
cstmt.registerOutParameter(4, Types.INTEGER);

cstmt.execute();

Call a function as a stored procedure

Create a wrapper procedure that calls test_in_out_function directly and assigns the result to an OUT parameter:

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);

Call a function using SELECT INTO

Create a wrapper procedure that calls test_in_out_function using 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();

Use a struct as a parameter

Starting from version 42.5.4.0.12 (2025-08-13), the driver supports the createStruct syntax. Pass composite types (also known as object types) as input parameters using a Struct object.

// Assume that conn is an established database connection object.
public void testSelectBoolean1() throws Exception {
  // 1. Prepare the attribute array for the struct.
  // The order and type of array elements must strictly match the test_object type defined in the database.
  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
      "This is a test string",                 // String
      new StringBuilder("Mutable string"),     // StringBuilder
      null,                                    // null
  };

  // 2. Use conn.createStruct to create a Struct object.
  Struct addressStruct = conn.createStruct("test_object", addressAttributes);

  // 3. Prepare and execute a CallableStatement to call the function.
  CallableStatement stmt = conn.prepareCall("{? = call test_object_func(?)}");
  stmt.registerOutParameter(1, Types.VARCHAR);
  stmt.setObject(2, addressStruct);
  stmt.execute();

  // 4. Get and print the function's return value.
  System.out.println(stmt.getObject(1).toString());

  stmt.close();
}

Connection parameters

The following parameters configure driver behavior at the connection level. All parameters follow the lifecycle of the Connection object.

ParameterDefaultDescription
autoCommittrueEnables or disables autocommit.
autoCommitSpecComplianttrueWhen true, allows commit/rollback calls even when autocommit is enabled.
blobAsByteatrueEnables Oracle-compatible BLOB handling.
clobAsTexttrueEnables Oracle-compatible CLOB handling.
collectWarningtrueCollects server warnings to prevent memory overflow from warning accumulation in loops.
defaultPolarMaxFetchSize0Works with MaxFetchSize to control the number of rows fetched per result set.
extraFloatDigitsSets the number of decimal digits for floating-point values.
mapDateToTimestamptrueMaps the Date type to Timestamp to preserve time information.
namedParamfalseEnables binding parameters using the :xxx format.
oracleCasefalseControls the case of returned column and table names. Valid values: false (no conversion), true (all uppercase), strict (uppercase only when all letters are lowercase).
resetNlsFormattrueRecognizes date, timestamp, and timestamptz types in the standard format by default.
boolAsIntfalseRepresents Boolean values as 1/0 (Oracle semantics) instead of true/false.

Data type handling

Date type

The kernel supports a 64-bit Date type with the same format as Oracle, including time information. The driver maps all Date types (Types.DATE or DATEOID) to timestamp for accurate processing.

Interval type

The community PostgreSQL driver does not support interval inputs in formats such as +12 12:03:12.111. PolarDB for PostgreSQL (Compatible with Oracle) supports this format, which is the standard output format in Oracle mode.

Number type

The standard java.sql specification does not include a getNumber function. Use getInt, setInt, and RegisterParam to pass Number type parameters as integers.

BLOB and CLOB types

BLOBs are processed as Bytea and CLOBs are processed as Text. The driver implements java.sql.Blob and java.sql.Clob interfaces with methods including getBytes, setBytes, position, and getBinaryStream.

Boolean type

The setBoolean interface uses true/false by default. Enable the boolAsInt parameter to switch to Oracle-compatible 1/0 semantics.

The numeric-to-Boolean conversion rules differ by driver version:

  • Version 42.5.4.0.10 and earlier: 1 = true, 0 = false, other values return an error.

  • Version 42.5.4.0.11 and later: 0 = false, all non-zero values = true (consistent with the Oracle driver).

PL/SQL support

The driver includes the following PL/SQL adaptations:

  • Stored procedures without `$$` symbols: Create FUNCTION or PROCEDURE objects without $$ delimiters. The / character is truncated during syntax parsing.

  • Colon-prefixed parameters: Pass parameters using the :xxx format, where xxx is a variable name.

  • Anonymous block parameter binding: Bind parameters within BEGIN ... END; blocks.

  • PL/SQL warning suppression: Prevent memory overflow caused by storing too many warning messages in a loop.

Framework integration

Hibernate

Configure the driver class and dialect in hibernate.cfg.xml:

Hibernate 3.6 or later is required for 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 column mapping: Map DATE columns to type="java.util.Date" in your .hbm.xml file to preserve time precision. Using type="date" causes loss of time precision.

<hibernate-mapping package="com.aliyun.polardb2.demo">
    <class name="TestTableEntity" table="test_table_name">
        <property name="currentDate" column="curr_date" type="java.util.Date"/>
    </class>
</hibernate-mapping>

LOB column mapping: PolarDB for PostgreSQL (Compatible with Oracle) 2.0 maps CLOB to text and BLOB to bytea. Specify the column type explicitly:

  • Java annotation:

    @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 connection pool

Druid has supported PolarDB since version 1.2.26.

Step 1: Add Druid to your pom.xml:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.26</version>
</dependency>

Step 2: Set the driver class name and database type when initializing the connection pool:

DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.aliyun.polardb2.Driver");
dataSource.setDbType("polardb2");

Step 3: (Optional) Configure the SQL firewall (WallFilter) to validate Oracle syntax and prevent SQL injection:

// Configure WallConfig.
WallConfig wallConfig = new WallConfig();
wallConfig.setStrictSyntaxCheck(true);              // Required: strict syntax checks.
wallConfig.setMultiStatementAllow(false);            // Disallow multiple statements per call.
wallConfig.setCommentAllow(true);                    // Allow comments.
wallConfig.setSelectIntoAllow(true);                 // Allow SELECT INTO.
wallConfig.setDeleteWhereNoneCheck(true);            // Check DELETE statements without WHERE conditions.

// Apply WallConfig to WallFilter.
WallFilter wallFilter = new WallFilter();
wallFilter.setConfig(wallConfig);

// Apply WallFilter to the connection pool.
DruidDataSource dataSource = new DruidDataSource();
dataSource.getProxyFilters().add(wallFilter);

To encrypt database passwords in Druid, see Encrypt database passwords.

WebSphere

Configure the PolarDB JDBC driver as a data source in WebSphere:

  1. For Database type, select User-defined.

  2. For Implementation class name, enter com.aliyun.polardb2.ds.PGConnectionPoolDataSource.

  3. For Class path, select the path to the JDBC JAR package.

Spring framework

From version 42.5.4.0.11 onward, pass a struct directly as a stored procedure parameter without extra configuration. The following example calls the get_user_info stored procedure, where parameter c is the composite type 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();
    }

    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); // Note: Calendar months start at 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

Connect PolarDB for PostgreSQL (Compatible with Oracle) clusters through Apache ShardingSphere for data sharding and read/write splitting. ShardingSphere natively supports the PostgreSQL protocol, which PolarDB is fully compatible with.

Requirements:

  • Set driverClassName to com.aliyun.polardb2.Driver.

  • Use driver version 42.5.4.0.12 (2025-08-13) or later.

  • Use the jdbc:postgresql protocol with forceDriverType=true.

The following is a YAML example (config-sharding.yaml) for configuring PolarDB data sources in ShardingSphere:

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

FAQ

Which JDBC driver should I use — the PolarDB driver or the open source community driver?

Use the PolarDB JDBC driver. PolarDB for PostgreSQL (Compatible with Oracle) implements Oracle-compatibility features at the driver level, including data type mappings, PL/SQL parameter binding, and CLOB/BLOB handling. The open source PostgreSQL driver does not support these features and will cause compatibility issues. Download the driver from the links in the Download the driver section.

Is the PolarDB JDBC driver available in public Maven repositories?

No. The only supported method to obtain the JDBC driver is to download its JAR package. For Maven projects, you must then manually install this JAR package into your local repository.

How do I check the driver version?

Run:

java -jar driver_name

Can I configure multiple IP addresses and ports in the URL?

Yes. Separate addresses with commas:

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

The driver attempts each address in order until a connection succeeds. If all addresses fail, the connection attempt fails. The default timeout per address is 10 seconds (connectTimeout). To change the timeout, add connectTimeout=<seconds> to the connection string.

Which cursor type should I use?

Use Types.REF for JDK earlier than 1.8 and Types.REF_CURSOR for JDK 1.8 or later.

How do I return column names in uppercase?

Add oracleCase=true to the connection string:

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

Update log

42.5.7.0.13 (2025-12-24)

  • Core upgrade: Synchronized to community 42.5.7, incorporating the latest security patches and performance optimizations.

  • Connection stability: Fixed a potential connection leak in specific connection pool scenarios.

  • Framework compatibility: Adjusted getDatabaseProductName to return PostgreSQL and DRIVER_NAME to return PolarDB-2.0 JDBC Driver, ensuring correct driver identification in frameworks such as MyBatis and Hibernate.

  • Driver conflict avoidance: Removed support for the jdbc:oracle:thin: protocol to eliminate conflicts with native Oracle drivers in multi-driver projects.

  • Oracle migration: Optimized the getTables interface to support looking up tables by uppercase table names. This feature adapts the Java business code logic migrated from Oracle to PolarDB and reduces the cost of application migration.

42.5.4.0.12 (2025-08-13)

  • Added support for using structs as parameters.

  • Added support for connecting using the jdbc:postgresql protocol.

42.5.4.0.10.11 (2025-07-10)

  • Added CallableStatement support for reading and writing functions and stored procedures, including IN, OUT, and INOUT parameters.

  • Added support for the SQLCODE error code field, compatible with the database kernel error handling mechanism.

  • Added support for Types.STRUCT in the Spring framework.

  • Optimized the numeric-to-Boolean conversion rule.

  • Enhanced type binding support.

42.5.4.0.10.9 (2025-03-19)

  • Added support for Oracle-style function parameter binding.

  • Fixed a bug where END caused parsing to fail.

42.5.4.0.10.7 (2025-01-06)

  • Added support for Oracle-compatible comments (for example, /* /* Comments */).

  • Fixed a Misuse of castNonNull issue caused by passing a null value in MyBatis calls to the CLOB interface.

42.5.4.0.10.6 (2024-12-04)

  • Added Channel Binding support for later JDBC versions.

  • Changed the default value of escapeSyntaxCallMode to callIfNoReturn to match Oracle parameter binding behavior.

  • Fixed incorrect attidentity identification that caused wrong column type retrieval.

42.5.4.0.10.5 (2024-10-24)

  • Optimized resetNlsFormat configuration to ensure correct setup during connection initialization and avoid unexpected entries in audit logs.

  • Fixed an error in logical replication tests caused by unrecognized java.nio.Buffer type interface.

  • Fixed incorrect parsing of CASE WHEN...END blocks in stored procedures.

42.5.4.0.10.4 (2024-09-02)

  • Fixed incorrect binding in PL blocks. This feature is disabled by default due to its performance impact.

  • Added implicit conversion within the same type group, allowing character types (such as VARCHAR and CHAR) and numeric types (such as NUMERIC, INTEGER, and DOUBLE) to be converted to each other as INOUT parameters.

  • Changed the getDatabaseProductName() return value to POLARDB2 Database Compatible with Oracle.

42.5.4.0.10.2 (2024-07-19)

  • Fixed a MyBatis issue where the database could not infer the parameter type when an object entity was registered as the Timestamp type.