日期:2014-05-16  浏览次数:20567 次

JDBC获取和操纵Oracle集合的方法

????? 上周需要在ibatis里调用oracle的一个存储过程,这个存储过程有一个参数是index table,需要实现TypeHandler或者TypeHandlerCallback。上网查g.cn一下,发现没有多少文章介绍,只有少数不全的,倒是有一篇鬼佬写的,比较详细,但只介绍到nested table的情况。Oracle里面三种集合类型,分别是variable array、nested table、index table,前两种已经有例子,但index table呢,如何实现?这让挺伤脑筋的!很自然的想到,看JDBC规范,发现没有相应扩展类型的介绍。想想,各大数据库厂商,都应该是有自己的JDBC实现和使用文档的。于是,上Oracle官网,下了好几篇文档。于是,在JDBC 3.0和4.0规范,Oracle8i、Oracle9i和Oracle10g的JDBC开发指引文档下,总算搞清楚了。既然费劲找到原因了,不写篇东西记下,对不起自己!加上年纪大了,记性不好,记下以后好翻查,而且自己一直说想写写技术文章的,种种原因,导致我这么多废话的记下这篇东西。
???? 首先,你如果是使用JDK6.0的话,那么你很幸运。JDK 6.0支持JDBC 4.0,这让你在这个问题面前,不用多几条白头发。如果是JDK5.0或者之前的版本,像我公司使用的是1.4,那么你就纠结了,需要使用Oracle的JDBC扩展去实现,像index table这种情况,还要依赖于你使用的Oracle JDBC Driver。相信很多时候,我们都是纠结的。当然,可能还有其他方法处理,因为我自己本身这类数据库应用开发经验很少。
???? 1. 通过Oracle的JDBC扩展实现获取和操纵Oracle集合
???? 不管是variable array或者nested table,在Java对应的实现,都是为JDBC里的Array类型,这两种类型后面补充。要注意,只能处理命名的集合类型。
???? 1.1确定你使用的Oracle数据库的版本
???? 你的数据库版本决定你能否操纵的集合类型。在Oracle8i的文档里,只有对Array类型进行说明,标题为“Working with Arrays”,显示没有集合这个概念。而Oracle9i的文档是,有专门的“Working with Oracle Collections”。
当然,我没有细看,文档查阅的也有限。在有限的了解下,得出只有Oracle9i以上的情况下,才有可能对index table类型支持。
???? 1.2其次是Driver的版本
???? 必须是JDBC OCI Driver才能支持。这部分文档在JDBC OCI Extensions里有介绍。支持常用的PL SQL的整数和字符串类型,类型列表文档也有列出。
???? 1.3使用OCI Driver下内置方法
???? 前面第1、2点满足后,使用OraclePreparedStatement和OracleCallableStatement内置方法支持,如下:
????

setPlsqlIndexTable()
registerIndexTableOutParameter()
getOraclePlsqlIndexTable()
getPlsqlIndexTable()

?

??? 把文档里的例子贴出来,看看也大概知道怎么使用。
??? 1.3.1?对于IN参数

????

// Prepare the statement
OracleCallableStatement procin = (OracleCallableStatement)
conn.prepareCall ("begin procin (?); end;");
// index-by table bind value
int[] values = { 1, 2, 3 };
// maximum length of the index-by table bind value. This
// value defines the maximum possible "currentLen" for batch
// updates. For standalone binds, "maxLen" should be the
// same as "currentLen".
int maxLen = values.length;
// actual size of the index-by table bind value
int currentLen = values.length;
// index-by table element type
int elemSqlType = OracleTypes.NUMBER;
// index-by table element length in case the element type
// is CHAR, VARCHAR or RAW. This value is ignored for other
// types.
int elemMaxLen = 0;
// set the value
procin.setPlsqlIndexTable (1, values,
maxLen, currentLen,
elemSqlType, elemMaxLen);
// execute the call
procin.execute ();

?
??? 1.3.2?对于OUT参数

????

// maximum length of the index-by table value. This
// value defines the maximum table size to be returned.
int maxLen = 10;
// index-by table element type
int elemSqlType = OracleTypes.NUMBER;
// index-by table element length in case the element type
// is CHAR, VARCHAR or RAW. This value is ignored for other
// types
int elemMaxLen = 0;
// register the return value
funcnone.registerIndexTableOutParameter
(1, maxLen, elemSqlType, elemMaxLen);

?????
??? 1.3.3?获取OUT参数的值
??? 有三个方法能获取index table(OUT参数)中的值,如下:
?? (1)?Object getPlsqlIndexTable (int paramIndex)
??? 该方法返回Object类型,强制类型转换为JDBC默认对应的Java类型。

???

// access the value using JDBC default mapping
BigDecimal[] values =
(BigDecimal[])funcnone.getPlsqlIndexTable (1);

?
???(2)?Datum[] getOraclePlsqlIndexTable (int paramIndex)
??? 该方法返回Oracel JDBC的类型,oracle.sql.Datum,使用该类获取相应类型的值。