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 version | Package |
|---|---|
| 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.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| Parameter | Example | Description |
|---|---|---|
| URL prefix | jdbc:polardb:// | The URL prefix for PolarDB connections. |
| Endpoint | pc-***.o.polardb.rds.aliyuncs.com | The cluster endpoint. For more information, see View or request an endpoint. |
| Port | 1521 | The default port for PolarDB clusters. |
| Database | polardb_test | The name of the database to connect to. |
| Username | test | The database account username. |
| Password | Pw123456 | The 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| Parameter | Example | Description |
|---|---|---|
| URL prefix | jdbc:postgresql:// | The URL prefix. |
| Endpoint | pc-***.o.polardb.rds.aliyuncs.com | The cluster endpoint. For more information, see View or request an endpoint. |
| Port | 1521 | The 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 type | Register | Set | Retrieve |
|---|---|---|---|
IN | Not required | setXXX(index, value) | Not retrievable |
IN OUT | registerOutParameter(index, type) | setXXX(index, value) | getXXX(index) |
OUT | registerOutParameter(index, type) | Not required | getXXX(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.
| Parameter | Default | Description |
|---|---|---|
autoCommit | true | Enables or disables autocommit. |
autoCommitSpecCompliant | true | When true, allows commit/rollback calls even when autocommit is enabled. |
blobAsBytea | true | Enables Oracle-compatible BLOB handling. |
clobAsText | true | Enables Oracle-compatible CLOB handling. |
collectWarning | true | Collects server warnings to prevent memory overflow from warning accumulation in loops. |
defaultPolarMaxFetchSize | 0 | Works with MaxFetchSize to control the number of rows fetched per result set. |
extraFloatDigits | — | Sets the number of decimal digits for floating-point values. |
mapDateToTimestamp | true | Maps the Date type to Timestamp to preserve time information. |
namedParam | false | Enables binding parameters using the :xxx format. |
oracleCase | false | Controls the case of returned column and table names. Valid values: false (no conversion), true (all uppercase), strict (uppercase only when all letters are lowercase). |
resetNlsFormat | true | Recognizes date, timestamp, and timestamptz types in the standard format by default. |
boolAsInt | false | Represents 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
FUNCTIONorPROCEDUREobjects without$$delimiters. The/character is truncated during syntax parsing.Colon-prefixed parameters: Pass parameters using the
:xxxformat, wherexxxis 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:
For Database type, select User-defined.
For Implementation class name, enter
com.aliyun.polardb2.ds.PGConnectionPoolDataSource.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
driverClassNametocom.aliyun.polardb2.Driver.Use driver version 42.5.4.0.12 (2025-08-13) or later.
Use the
jdbc:postgresqlprotocol withforceDriverType=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: 2FAQ
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_nameCan 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/postgresThe 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=trueUpdate 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
getDatabaseProductNameto returnPostgreSQLandDRIVER_NAMEto returnPolarDB-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
getTablesinterface 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:postgresqlprotocol.
42.5.4.0.10.11 (2025-07-10)
Added
CallableStatementsupport 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.STRUCTin 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
ENDcaused 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 castNonNullissue caused by passing a null value in MyBatis calls to the CLOB interface.
42.5.4.0.10.6 (2024-12-04)
Added
Channel Bindingsupport for later JDBC versions.Changed the default value of
escapeSyntaxCallModetocallIfNoReturnto match Oracle parameter binding behavior.Fixed incorrect
attidentityidentification that caused wrong column type retrieval.
42.5.4.0.10.5 (2024-10-24)
Optimized
resetNlsFormatconfiguration 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.Buffertype interface.Fixed incorrect parsing of
CASE WHEN...ENDblocks 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
VARCHARandCHAR) and numeric types (such asNUMERIC,INTEGER, andDOUBLE) to be converted to each other asINOUTparameters.Changed the
getDatabaseProductName()return value toPOLARDB2 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
Timestamptype.