本文将介绍如何在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的生命周期生效。
参数名 | 说明 |
autoCommit | 开启或关闭参数形式的自动提交。取值如下:
|
autoCommitSpecCompliant | 是否允许自动提交下继续调用commit/rollback方法。取值如下:
|
blobAsBytea | 是否支持Oracle兼容的BLOB。取值如下:
|
clobAsText | 是否支持Oracle兼容的CLOB。取值如下:
|
collectWarning | 是否收集告警(防止内存溢出)。取值如下:
|
defaultPolarMaxFetchSize | 配合MaxFetchSize实现结果集条数控制,默认值为0。 |
extraFloatDigits | 小数长度。 |
forceDriverType | 强制驱动按照某一种方案去解析。取值为pg、ora、ora11和ora14。 |
mapDateToTimestamp | 是否支持将Date类型转为Timestamp。取值如下:
|
namedParam | 是否支持通过
|
oracleCase | 是否返回列名、表名的大写。取值如下:
|
resetNlsFormat | 是否支持将
|
unnamedProc | 是否支持匿名块绑定参数功能。取值如下:
|
boolAsInt | 支持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兼容的数据库交互需求。
PL/SQL适配
支持不带$$符号的存储过程。
支持在创建
FUNCTION
/PROCEDURE
等过程时省略$$
符号,并支持在语法解析时截断/
字符。支持冒号变量名作为参数。
支持使用
:xxx
这种方式传递参数,其中xxx
为冒号开头的变量名。支持匿名块绑定参数。
支持屏蔽PLSQL的警告信息。
防止循环中存储过多的警告信息导致内存超限。
示例
加载JDBC驱动
在应用中执行以下命令加载JDBC驱动:
Class.forName("com.aliyun.polardb2.Driver");
如果是通过项目导入的方式导入JDBC,以上驱动都会自动注册完成,不需要额外注册。
连接数据库
在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集群用户名对应的密码。 |
查询并处理结果
访问数据库执行查询时,需要创建一个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));
}
使用OUT参数
访问数据库存储过程时,如果要使用带有OUT参数的存储过程,需要创建CallableStatement对象。并使用
registerOutParameter,使用示例如下:
String sql = "CREATE or replace PROCEDURE test_in_out_procedure(a IN integer, b INOUT integer, c OUT integer)\n" +
"AS $$\n" +
"BEGIN\n" +
" c = a + b;\n" +
" b = a;\n" +
"return;\n" +
"END;\n" +
"$$;";
conn.createStatement().execute(sql);
CallableStatement stmt = conn.prepareCall("{call test_in_out_procedure(?,?,?)}");
stmt.setInt(1, 1);
stmt.setInt(2, 2);
stmt.registerOutParameter(2, Types.INTEGER);
stmt.registerOutParameter(3, Types.INTEGER);
stmt.execute();
System.out.println("get $2 = " + stmt.getInt(2));
System.out.println("get $3 = " + stmt.getInt(3));
// OUTPUT:
// get $2 = 1
// get $3 = 3
相关工具适配
适配Hibernate
如果您的工程使用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
类型的列,需要在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>
Druid连接池
Druid 1.1.24之前的版本,需要显式设置driver name
和dbtype
参数,如下所示:
dataSource.setDriverClassName("com.aliyun.polardb2.Driver");
dataSource.setDbType("postgresql");
Druid 1.1.24之前版本没有适配PolarDB,因此dbtype
需要设置为postgresql
。
如果您需要在Druid连接池中对数据库密码进行加密,请参见数据库密码加密。
适配WebSphere
使用WebSphere时,配置PolarDB的JDBC作为数据源,步骤如下所示:
数据库类型选择用户自定义的。
实现类名为:
com.aliyun.polardb2.ds.PGConnectionPoolDataSource
。类路径选择JDBC jar包所在路径。
常见问题
如何选择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
版本更新日志
版本45.4.0.10.5(2024-10-24)
优化
resetNlsFormat
参数的设置,确保连接时的正确配置。同时,避免在审计日志中留下非预期的执行记录。修复逻辑复制测试中因无法识别
java.nio.Buffer
类型接口而导致的错误。修复存储过程中
CASE WHEN...END
识别结束解析不正确的问题。
版本45.4.0.10.4(2024-09-02)
修复了PL块中绑定不正确的问题。针对此问题对性能的影响,默认已关闭该功能。
支持在同一类型内部进行隐式转换,允许字符类型(如
VARCHAR
、CHAR
)和数字类型(如NUMERIC
、INTEGER
、DOUBLE
)作为INOUT
参数相互转换。驱动中元信息的
getDatabaseProductName()
函数返回值现为:“POLARDB2 Database Compatible with Oracle
”。
版本45.4.0.10.2(2024-07-19)
修复了在
Mybatis
中,当对象实体注册类型为Timestamp
时,数据库无法正确推断参数类型的问题。
专家面对面
关于JDBC,如果您在使用过程中有任何问题,请进钉钉群咨询。钉钉群号:71365019522。