本文將介紹如何在Java應用中使用JDBC連接PolarDB PostgreSQL版(兼容Oracle)數據庫。
前提條件
背景信息
JDBC(Java Database Connectivity)為Java應用程序提供了訪問數據庫的編程接口。PolarDB PostgreSQL版(兼容Oracle)數據庫的JDBC是基于開源的PostgreSQL JDBC開發而來,使用PostgreSQL本地網絡協議進行通信,允許Java程序使用標準的、獨立于數據庫的Java代碼連接數據庫。
JDBC驅動程序使用了PostgreSQL 3.0協議,與Java 6(JDBC 4.0)、Java 7(JDBC4.1)和Java 8(JDBC4.2)兼容。
下載JDBC
阿里云提供了兼容Java 6、Java 7和Java 8三個Java版本的JDBC驅動,對應三個Jar包,包名分別為polardb-jdbc16.jar
、polardb-jdbc17.jar
和polardb-jdbc18.jar
。您可根據應用使用的JDK版本選擇合適的JDBC。
配置JDBC
在Java應用中使用JDBC前,需要將JDBC驅動包的路徑添加至CLASSPATH
中。例如您的JDBC驅動放置的路徑為/usr/local/polardb/share/java/,在CLASSPATH
中添加JDBC驅動路徑的命令如下:
export CLASSPATH=$CLASSPATH:/usr/local/polardb/share/java/<安裝的Jar包名.jar>
示例:
export CLASSPATH=$CLASSPATH:/usr/local/polardb/share/java/polardb-jdbc18.jar
您可以通過如下命令查看當前使用的JDBC版本:
#java -jar <安裝的Jar包名.jar>
示例:
#java -jar polardb-jdbc18.jar
POLARDB JDBC Driver 42.2.XX.XX.0
訪問PolarDB
示例
package com.aliyun.polardb; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; /** * POLARDB JDBC DEMO * <p> * Please make sure the host ip running this demo is in you cluster's white list. */ public class PolarDBJdbcDemo { /** * Replace the following information. */ private final String host = "***.o.polardb.rds.aliyuncs.com"; private final String user = "***"; private final String password = "***"; private final String port = "1521"; private final String database = "db_name"; public void run() throws Exception { Connection connect = null; Statement statement = null; ResultSet resultSet = null; try { Class.forName("com.aliyun.polardb.Driver"); Properties props = new Properties(); props.put("user", user); props.put("password", password); String url = "jdbc:polardb://" + host + ":" + port + "/" + database; connect = DriverManager.getConnection(url, props); /** * create table foo(id int, name varchar(20)); */ String sql = "select id, name from foo"; statement = connect.createStatement(); resultSet = statement.executeQuery(sql); while (resultSet.next()) { System.out.println("id:" + resultSet.getInt(1)); System.out.println("name:" + resultSet.getString(2)); } } catch (Exception e) { e.printStackTrace(); throw e; } finally { try { if (resultSet != null) resultSet.close(); if (statement != null) statement.close(); if (connect != null) connect.close(); } catch (SQLException e) { e.printStackTrace(); throw e; } } } public static void main(String[] args) throws Exception { PolarDBJdbcDemo demo = new PolarDBJdbcDemo(); demo.run(); } }
加載JDBC驅動
在應用中執行以下命令加載 JDBC 驅動:
Class.forName("com.aliyun.polardb.Driver");
連接數據庫
在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集群用戶名對應的密碼。
查詢并處理結果
訪問數據庫執行查詢時,需要創建一個
Statement
、PreparedStatment
或者CallableStatement
對象。上述示例中使用了
Statement
,使用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)); }
CallableStatement
用于處理存儲過程,示例如下:String sql = "{?=call getName (?, ?, ?)}"; CallableStatement stmt = conn.prepareCall(sql); stmt.registerOutParameter(1, java.sql.Types.INTEGER); //Bind IN parameter first, then bind OUT parameter int id = 100; stmt.setInt(2, id); // This would set ID as 102 stmt.registerOutParameter(3, java.sql.Types.VARCHAR); stmt.registerOutParameter(4, java.sql.Types.INTEGER); //Use execute method to run stored procedure. stmt.execute(); //Retrieve name with getXXX method String name = stmt.getString(3); Integer msgId = stmt.getInt(4); Integer result = stmt.getInt(1); System.out.println("Name with ID:" + id + " is " + name + ", and messegeID is " + msgId + ", and return is " + result);
以上代碼使用的存儲過程
getName
如下:CREATE OR REPLACE FUNCTION getName( id In Integer, name Out Varchar2, result Out Integer ) Return Integer Is ret Int; Begin ret := 0; name := 'Test'; result := 1; Return(ret); End;
說明當存儲過程為游標類型時,不同的Java版本對應的游標類型不同:
Java8及以后的版本使用
Types.REF_CURSOR
類型游標。Java8之前的版本使用
Types.REF
類型游標。
設置FetchSize
默認情況下,驅動會一次性從數據庫端獲取所有數據,對于數據量很大的查詢,這會占用客戶端大量內存,甚至造成 OOM,為避免此類情況,JDBC提供了基于游標的ResultSet,批量獲取數據集。使用方法如下:
設置FetchSize,FetchSize默認為0,即獲取所有數據。
設置連接的autoCommit為false。
// make sure autocommit is off conn.setAutoCommit(false); Statement st = conn.createStatement(); // Set fetchSize to use cursor st.setFetchSize(50); ResultSet rs = st.executeQuery("SELECT * FROM mytable"); while (rs.next()) { System.out.print("a row was returned."); } rs.close(); // Reset fetchSize to turn off the cursor st.setFetchSize(0); rs = st.executeQuery("SELECT * FROM mytable"); while (rs.next()) { System.out.print("many rows were returned."); } rs.close(); // Close the statement. st.close();
Maven工程
如果您的Java項目使用Maven構建,可以通過如下命令將PolarDB的JDBC驅動包安裝至您的本地倉庫:
mvn install:install-file -DgroupId=com.aliyun -DartifactId=<安裝的Jar包名> -Dversion=1.1.2 -Dpackaging=jar -Dfile=/usr/local/polardb/share/java/<安裝的Jar包名.jar>
示例:
mvn install:install-file -DgroupId=com.aliyun -DartifactId=polardb-jdbc18 -Dversion=1.1.2 -Dpackaging=jar -Dfile=/usr/local/polardb/share/java/polardb-jdbc18.jar
在Maven工程的pom.xml
文件中添加如下依賴。
<dependency>
<groupId>com.aliyun</groupId>
<artifactId><安裝的Jar包名></artifactId>
<version>1.1.2</version>
</dependency>
示例:
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>polardb-jdbc18</artifactId>
<version>1.1.2</version>
</dependency>
Hibernate
如果您的工程使用Hibernate連接數據庫,請在您的Hibernate配置文件hibernate.cfg.xml
中配置PolarDB數據庫的驅動類和方言。
Hibernate需要為3.6及以上版本才支持PostgresPlusDialect方言。
<property name="connection.driver_class">com.aliyun.polardb.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>
Druid連接池
Druid 1.1.24及其之后的版本默認支持PolarDB的驅動,無需設置
driver name
和dbtype
參數。Druid 1.1.24之前的版本,需要顯式設置
driver name
和dbtype
參數,如下所示:dataSource.setDriverClassName("com.aliyun.polardb.Driver"); dataSource.setDbType("postgresql");
說明Druid 1.1.24之前版本沒有適配PolarDB,因此
dbtype
需要設置為postgresql
。
如果您需要在Druid連接池中對數據庫密碼進行加密,請參見數據庫密碼加密。
適配Activiti
如果您的應用使用了業務流程管理框架Activiti,在PolarDB數據源初始化時,可能會出現以下錯誤信息。
couldn't deduct database type from database product name 'POLARDB Database Compatible with Oracle'
這是因為Activiti內置了一些數據庫版本信息和數據庫類型的映射關系,導致無法正確映射PolarDB版本信息。您可以通過設置SpringProcessEngineConfiguration
子類,在該子類中重載buildProcessEngine
的方法來解決問題。在該解決方法中,您需要顯式指定數據庫類型,配置方法請參見以下示例。
package com.aliyun.polardb;
import org.activiti.engine.ProcessEngine;
import org.activiti.spring.SpringProcessEngineConfiguration;
public class PolarDBSpringProcessEngineConfiguration extends SpringProcessEngineConfiguration {
public PolarDBSpringProcessEngineConfiguration() {
super();
}
@Override
public ProcessEngine buildProcessEngine() {
setDatabaseType(DATABASE_TYPE_POSTGRES);
return super.buildProcessEngine();
}
}
將SpringProcessEngineConfiguration
子類放在您的工程中,在配置文件中設置使用該類加載配置,并初始化引擎,具體信息請參見以下示例。
<bean id="processEngineConfiguration" class="com.aliyun.polardb.PolarDBSpringProcessEngineConfiguration">
<property name="dataSource" ref="dataSource"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="databaseSchemaUpdate" value="true"/>
<!-- 其他配置在此省略 -->
</bean>
適配Quartz
Quartz是一款開源的作業調度庫,使用Quartz連接PolarDB時,需要將org.quartz.jobStore.driverDelegateClass
配置為 org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
,如下所示:
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
適配WebSphere
使用 WebSphere時,配置PolarDB的JDBC作為數據源,步驟如下所示:
數據庫類型選擇用戶自定義的。
實現類名為:
com.aliyun.polardb.ds.PGConnectionPoolDataSource
。類路徑選擇JDBC jar包所在路徑。
適配MyBatis
使用MyBatis時,可能需要配置databaseIdProvider,默認配置如下所示:
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>
databaseIdProvider的目的是提供一個數據庫產品名到特定名稱(即databaseId)的映射關系,即便數據庫的產品名因數據庫版本變化而發生改變,也可以映射到相同的名稱。
在MyBatis的XML映射文件中,可以為SQL語句指定databaseId屬性,說明該SQL僅能夠在該databaseId對應的數據庫上執行。因此,在加載XML映射文件時,MyBatis僅加載databaseId與當前數據庫匹配的SQL語句,如果SQL語句沒有設置databaseId屬性則總是會被加載。
因此,如果XML映射文件中的SQL均沒有指定databaseId,默認配置信息可以不做任何修改。如果需要通過databaseId識別特定于PolarDB執行的SQL,則可以添加如下配置信息,并在XML映射文件中使用polardb作為SQL的databaseId。
<property name="POLARDB" value="polardb" />
常見問題
Q:如何選擇JDBC驅動,是否可以使用開源社區驅動?
A:PolarDB PostgreSQL版(兼容Oracle)兼容版在開源PostgreSQL的基礎上實現了眾多兼容性相關的特性,有些特性需要驅動層配合實現,因此,推薦使用PolarDB的JDBC驅動。相關驅動可以在官網驅動下載頁面下載。
Q:公共Maven倉庫是否有PolarDB JDBC驅動?
A:按照官網描述,JDBC驅動需要在官網下載jar包,對于Maven工程需要手動安裝該jar包至本地倉庫使用,目前僅支持官網下載JDBC驅動包一種方式。
Q:如何查看版本號?
A:通過運行
java -jar 驅動名
來查看版本號。Q:是否支持在URL中配置多個IP和端口?
A:PolarDB PostgreSQL版(兼容Oracle)的JDBC驅動支持在URL中配置多個IP和端口,示例如下:
jdbc:poalardb://1.2.XX.XX:5432,2.3.XX.XX:5432/postgres
說明配置多個IP后,創建連接時會依次嘗試通過這些IP創建連接,若都不能創建連接,則連接創建失敗。每個IP嘗試創建連接的超時時間默認為10s,即connectTimeout,若要修改超時時間,可在連接串中添加該參數進行設置。
Q:游標類型如何選擇?
A:如果是java 1.8之前的JDK,使用Types.REF;如果是java 1.8及其之后的版本,可以使用Types.REF_CURSOR。
Q:是否支持默認返回大寫的列名?
A:可以在JDBC連接串中添加參數
oracleCase=true
,該參數會將返回的列名默認轉換為大寫,示例如下:jdbc:poalardb://1.2.XX.XX:5432,2.3.XX.XX:5432/postgres?oracleCase=true