本文将介绍如何在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