本文将介绍在Java应用中使用JDBC连接PolarDB兼容Oracle数据库。

前提条件

  • 已经在PolarDB集群创建用户,如何创建用户请参见创建数据库账号
  • 已经将需要访问PolarDB集群的主机IP地址添加到白名单,如何添加白名单请参见设置集群白名单

背景信息

JDBC(Java Database Connectivity)为Java应用程序提供了访问数据库的编程接口。PolarDB兼容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.jarpolardb-jdbc17.jarpolardb-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.5.2.0

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连接池时,需要显式设置driver namedbtype参数,如下所示:

dataSource.setDriverClassName("com.aliyun.polardb.Driver");
dataSource.setDbType("polardb");
说明 如果您使用的是Druid 1.1.22以前的版本,dbType参数需要设置为postgresql

适配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>

加载JDBC驱动

Class.forName("com.aliyun.polardb.Driver");

示例

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 = "1921";
  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中,一个数据库通常用一个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集群用户名对应的密码。

访问数据库执行查询时,需要创建一个StatementPreparedStatment或者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;