本文將介紹如何在Java應用中使用JDBC串連PolarDB PostgreSQL版(相容Oracle)資料庫。
前提條件
背景資訊
JDBC(Java Database Connectivity)為Java應用程式提供了訪問資料庫的編程介面。PolarDB PostgreSQL版(相容Oracle)資料庫的JDBC是基於開源的PostgreSQL JDBC開發而來,使用PostgreSQL本網協議進行通訊,允許Java程式使用標準的、獨立於資料庫的Java代碼串連資料庫。
下載驅動
JDK版本 | 軟體包 |
1.6 | |
1.7 | |
1.8 |
由於安全原因,相容Oracle文法相容1.0版本的驅動已經下線。如需協助,請聯絡我們處理。
Maven配置
目前PolarDB的JDBC驅動尚未在公開的Maven倉庫中提供,當前僅支援通過上傳JAR包的方式進行配置。
功能介紹
串連級參數功能
以下功能都通過一個串連參數配置,支援的參數如下表所示。所有的新增參數的生效範圍都控製為串連層級,隨Connection的生命週期生效。
參數名 | 說明 |
| 開啟或關閉參數形式的自動認可。取值如下:
|
| 是否允許自動認可下繼續調用commit/rollback方法。取值如下:
|
| 是否支援Oracle相容的BLOB。取值如下:
|
| 是否支援Oracle相容的CLOB。取值如下:
|
| 是否收集警示(防止記憶體溢出)。取值如下:
|
| 配合 |
| 小數長度。 |
| 是否支援將Date類型轉為Timestamp。取值如下:
|
| 是否支援通過
|
| 是否返回列名、表名的大寫。取值如下:
|
| 是否支援將
|
| 支援Oracle語義的布爾值表示方式。取值如下:
|
資料類型解析
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的警告資訊。
防止迴圈中儲存過多的警告資訊導致記憶體超限。
樣本
載入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,使用 |
串連地址 | 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,使用 |
串連地址 | pc-***.o.polardb.rds.aliyuncs.com | PolarDB叢集的串連地址,如何查看串連地址請參見查看或申請串連地址。 |
連接埠 | 1521 | PolarDB叢集的連接埠,預設為1521。 |
查詢並處理結果
訪問資料庫執行查詢時,需要建立一個Statement、PreparedStatment或者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擷取方式 |
| 無需註冊 |
| 不可擷取 |
|
|
|
|
|
| 無需設定 |
|
預存程序調用樣本
叢集中建立一個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讀寫PolarDB的DATE類型資料時保留時分秒精度。如果直接使用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串連時,為確保功能的完整性和穩定性,請注意以下關鍵配置:
Druid是從
1.2.26版本開始支援PolarDB的,請確保您專案中引用的版本不低於此版本。以Maven為例:<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.26</version> </dependency>在初始化串連池時,必須顯式設定驅動類名(
driverClassName)和資料庫類型(dbType)。DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName("com.aliyun.polardb2.Driver"); dataSource.setDbType("polardb2");使用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);如果需要在Druid串連池中對資料庫密碼進行加密,請參見資料庫密碼加密。
適配WebSphere
使用WebSphere時,配置PolarDB的JDBC作為資料來源,步驟如下所示:
資料庫類型選擇使用者自訂的。
實作類別名為:
com.aliyun.polardb2.ds.PGConnectionPoolDataSource。類直接選取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.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)
支援使用jdbc:postgresql協議串連叢集。
42.5.4.0.10.11(2025-07-10)
支援通過CallableStatement介面讀寫函數以及預存程序,支援各種類型的IN&OUT&INOUT參數。
支援SQLCODE錯誤碼欄位,與資料庫核心的錯誤處理機制相容。
支援Spring架構中使用Types.STRUCT結構體。
最佳化數字類型到布爾值的轉換規則。
增強型別綁定支援。
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塊中綁定不正確的問題。針對此問題對效能的影響,預設已關閉該功能。
支援在同一類型內部進行隱式轉換,允許字元類型(如
VARCHAR、CHAR)和數字類型(如NUMERIC、INTEGER、DOUBLE)作為INOUT參數相互轉換。驅動中元資訊的
getDatabaseProductName()函數傳回值現為:“POLARDB2 Database Compatible with Oracle”。
42.5.4.0.10.2(2024-07-19)
修複了在
Mybatis中,當對象實體註冊類型為Timestamp時,資料庫無法正確推斷參數類型的問題。