ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 使用 DB2 JCC 驱动新功能操作 XML 数据

使用 DB2 JCC 驱动新功能操作 XML 数据

原创 Linux操作系统 作者:ArtCode 时间:2009-04-16 17:10:18 0 删除 编辑

概述

XML(Extensible Markup Language)即可扩展标记语言,是 Internet 环境中跨平台的,依赖于内容的技术,是当前处理结构化文档信息的有力工具,在 Java 应用开发中使用非常广泛。 DB2 Version 9 开始将 XML 纳入了内置数据类型,全面增强了对 XML 数据的支持。 JCC(Java Common Connectivity)驱动作为 DB2 的官方 JDBC 驱动,也相应的提供了操作 XML 数据的接口。

IBM JCC(Java Common Connectivity)驱动,全称“ IBM DB2 Universal Driver ”,在最新的版本 4 中,改名为“ IBM Data Server Driver for JDBC and SQLJ ”。在 JDBC4.0 规范出台之前,JCC 驱动就已经提供操作关系型数据库中 XML 类型数据的支持,将 XML 数据映射成其他 Java 中已存在的数据类型。目前,JCC 驱动版本 4 对 JDBC4.0 规范中的 XML 接口提供了全面支持。

环境配置

开发和运行操作 XML 数据的 Java 应用,应该使用 DB2 Version 9 及以上版本,包括 DB2 for Unix,Linux 和 Windows Version 9(Vipper),Version9.5(VipperII)和 DB2 for z/OS Version 9,这些版本的 DB2 都内置了 XML 数据类型。如果只使用 JCBC4.0 规范颁布之前的 XML 功能,JCC 驱动的版本 3m(同 DB2 for LUW V9 一同发布)或者版本 3(同 DB2 for LUW V9.5 一同发布)就可实现,如果使用 JDBC4.0 规范中的新功能,则需要 JCC 驱动的版本 4(与 DB2 for LUW V9.5 一同发布)。 JCC 驱动版本 3m 和版本 3 需要 JDK1.4 的支持,而 JCC 驱动版本 4 则需要 JDK1.6 。

JDBC4.0 规范颁布之前 JCC 驱动对 XML 的支持

在 JDBC4 标准出台之前,Java 中没有与 XML 对应的数据类型,因此在 JCC 驱动中,采用数据类型映射的方式对 XML 数据进行操作。通过些接口中 XML 数据被映射成 Java string, byte[],stream 与 JCC 中引入的 com.ibm.db2.DB2Xml 接口。

要操作数据库中的 XML 数据,首先要建立到数据库的连接。使用 JCC 驱动获取到 DB2 的连接,可以通过 DriverManger 或者 DataSource 接口来实现。在清单 1 中,我们使用了 JCC 驱动中实现了 DataSource 接口的 DB2SimpleDataSource 来获取连接。


清单 1. 使用了 JCC 驱动获取链接

DB2SimpleDataSource ds =newDB2SimpleDataSource(); 
 ds.setServerName("localhost"); 
 ds.setPortNumber(50000); 
 ds.setDatabaseName("XMLDB"); 
 ds.setUser("username"); 
 ds.setPassword("password"); 
 ds.setTraceFile("C:\\work\\temp\\trace.txt"); 
 ds.setTraceLevel(DB2BaseDataSource.TRACE_ALL); 
 ds.setDriverType(4); 
 ds.setSecurityMechanism((short)3); 
 Connection con = ds.getConnection();

接下来清单 2 在数据库中创建一个包含 XML 数据类型的表。


清单 2. 创建 XML 数据类型的表

String ddlStr = "CREATE TABLE XMLTABLE " 
+ "(ROWNUM INTEGER NOT NULL, XMLCOL1 XML, XMLCOL2 XML, XMLCOL3 XML)"; 
 Statement stat = con.createStatement(); 
 stat.executeUpdate(ddlStr);

设置 XML 数据

当在 Java 应用中操作 XML 列的数据时,无论是插入还是修改,输入数据都要转换成序列化的字符或者字节串的形式,或者构造成 DB2Xml 的实例。 JCC 驱动在 PreparedStatement 中提供了表 1 中的方法,来接收 XML 数据的输入。


表 1. JCC 驱动接收 XML 数据的方法

方法 输入参数的数据类型
PreparedStatement.setAsciiStream InputStream
PreparedStatement.setBinaryStream InputStream
PreparedStatement.setBytes byte[]
PreparedStatement.setCharacterStream Reader
PreparedStatement.setString String
PreparedStatement.setObject byte[],Blob,Clob,DB2Xml,InputStream,Reader,String
PreparedStatement.setBlob Blob
PreparedStatement.setClob Clob

XML 数据区别于普通字符串数据的关键点之一是,XML 数据的编码可能来自自身定义,而普通字符串数据则全部采用外部编码,既开发语言中使用的编码。 XML 的内部编码(XMLSIE)是指在 XML 文件声明中指定的编码方式,例如“ ”中的 encoding= ” UTF8 ”就指定了该 XML 文件使用的内部编码是“ UTF8 ”。 在 Java 应用中,XML 数据的外部编码(XMLSEE)始终是 Unicode 。当 XML 数据以字符串方式传送(setString,setAsciiStream,setCharacterStream)时,被认为使用外部编码;以字节串方式传送(setBytes,setBinaryStream)时,被认为使用内部编码。

向 XMLTABLE 中插入数据时,可以使用方法 setAsciiStream,setBinaryStream,setCharacterStream 直接从文件插入 XML 数据,也可以将 XML 文件的内容转换成 String,Bytes 数组或者 lob 对象后,使用对应的 setter 方法设置。清单 3 向表 XMLTABLE 插入了一行数据,对三个 XML 列,分别使用了 setString,setBinarySteam 和 setCharacterStream 三个接口。


清单 3. 向 XMLTABLE 中插入数据

// 向 XMLTABLE 中插入一行
 PreparedStatement pstat = con.prepareStatement("INSERT INTO XMLTABLE " 
+ "(ROWNUM, XMLCOL1, XMLCOL2,XMLCOL3) VALUES (?,?,?,?)"); 
 InputStream ins =null; 
 Reader rd =null; 
 String xmlString = "";//从文件中读取XML数据,构造成String类型的数据try{ 
	 FileReader file =newFileReader("C:\\work\\temp\\testfile1.xml"); 
	 BufferedReader br =newBufferedReader(file); String line =null;
while((line = br.readLine()) !=null) { xmlString += line; } br.close(); file.close(); 
 }catch(java.io.IOException e) {throw
				newSQLException(e.getMessage()); 
 }//XML文件构造成InputSteam实例try{ 
	 ins =newFileInputStream(newFile("C:\\work\\temp\\testfile2.xml")); 
 }catch(java.io.IOException e) {throw
				newSQLException(e.getMessage()); 
 }//XML文件构造成Reader实例try{ rd =newFileReader(newFile("C:\\work\\temp\\testfile3.xml")); 
 }catch(java.io.IOException e) {throw
				newSQLException(e.getMessage()); 
 } // 设置参数值
 pstat.setInt(1, 1); 
 pstat.setString(2, xmlString); 
 pstat.setBinaryStream(3, ins, (newFile("C:\\work\\temp\\testfile2.xml")).length()); 
 pstat.setCharacterStream(4, rd, (newFile("C:\\work\\temp\\testfile3.xml")).length()); 
 pstat.executeUpdate();

获取 XML 数据

当执行一个包含 XML 类型列的查询后,返回的结果中包含的 XML 数据同样可以通过数据类型映射的方法取出,在 JCC 驱动的 ResultSet 中提供了表 2 中的方法,通过将 XML 数据转化成 Steam,String 或者 DB2Xml 实例,来获取数据集中的 XML 数据。

表 2. 获取 XML 数据的方法

方法 输出结果的数据类型
ResultSet.getAsciiStream InputStream
ResultSet.getBinaryStream InputStream
ResultSet.getBytes byte[]
ResultSet.getCharacterStream Reader
ResultSet.getObject com.ibm.db2.jcc.DB2Xml
ResultSet.getString String

为了弥补 JDBC4 标准之前 JDBC 中没有与 XML 数据对应类的问题,JCC 驱动引入了一个新的接口 com.ibm.db2.jcc.DB2Xml 。当应用使用 getObject 方法获取 XML 数据时,会返回 DB2Xml 实例,通过 DB2Xml 接口定义的 getter 方法可以获得当前列的 XML 数据,还可以制定 XML 的内部编码声明。

表 3 中是描述了 DB2Xml 接口中定义的方法,返回类型以及对返回的 XML 数据编码的指定。


表 3. 返回 XML 数据的方法

方法 输出数据类型 增加的XML内部编码声明
DB2Xml.getDB2AsciiStream InputStream None
DB2Xml.getDB2BinaryStream InputStream None
DB2Xml.getDB2Bytes byte[] None
DB2Xml.getDB2CharacterStream Reader None
DB2Xml.getDB2String String None
DB2Xml.getDB2XmlAsciiStream InputStream US-ASCII
DB2Xml.getDB2XmlBinaryStream InputStream 通过 targetEncoding 参数设置
DB2Xml.getDB2XmlBytes byte[] 通过 targetEncoding 参数设置
DB2Xml.getDB2XmlCharacterStream Reader ISO-10646-UCS-2
DB2Xml.getDB2XmlString String ISO-10646-UCS-2

在获取 DB2Xml 实例之后,可以使用其定义的 getter 方法获取当前行的 XML 数据。 DB2Xml 接口在支持 JDBC4.0 规范的 JCC 驱动版本 4 中已经不被推荐使用。

在清单 5 中,将分别使用 getBinaryStream,getCharacterStream 和 getObject 方法来获取数据集当前行中 XML 数据,并将其转化成可读的字符串。


清单 5. XML 数据处理方法

PreparedStatement pstat = con.prepareStatement("SELECT XMLCOL1,XMLCOL2 " 
+ ",XMLCOL3 FROM DB2ADMIN.XMLTABLE WHERE ROWNUM = ?"); 
 pstat.setInt(1, 1); 
 ResultSet rs = pstat.executeQuery(); 
 rs.next(); String verifyString1,verifyString2,verifyString3; 
 InputStream ins = rs.getBinaryStream("XMLCOL1"); 
 Reader rd = rs.getCharacterStream("XMLCOL2"); 
 DB2Xml db2Xml = (DB2Xml)rs.getObject("XMLCOL3"); 
 BufferedReader br =newBufferedReader(newInputStreamReader(ins)); 
 // 使用 BufferedReader 的方法读取列 XMLCOL1 中的数据
……
 br =newBufferedReader(rd); 
 // 使用 BufferedReader 的方法读取列 XMLCOL2 中的数据
……
 // 通过 DB2Xml 的 getString 方法获取 XMLCOL3 中的数据
 verifyString3 = db2Xml.getString();

在存储过程中使用 XML 数据

在 DB2 for Unix,Linux 和 Windows V9 及以上版本中无论是 SQL 或外部存储过程,还是用户自定义函数都可以包括 XML 类型的参数,DB2 for z/OS V9 还不支持使用内置 XML 类型作为存储过程的参数。对于 SQL 存储过程,存储过程定义的参数中包含 XML 类型参数。对于外部存储过程或者用户自定义函数或者过程定义中的 XML 参数有 XML AS CLOB 类型。在调用包含 XML 参数的存储过程或者用户自定义函数时,需要在调用语句中使用兼容的数据类型。

从 JDBC 程序中调用含 XML 输入参数的过程,使用 com.ibm.db2.jcc.DB2Xml 类型的参数;注册 XML 输出参数,需要注册参数为 com.ibm.db2.jcc.DB2Types.XML 数据类型。

清单 6 的程序中调用了一个包含三个 XML 参数的存储过程,一个输入参数,一个输出参数,一个输入 / 输出参数。


清单 6. XML 参数调用实例

com.ibm.db2.jcc.DB2Xml in_xml = xmlvar; 
 com.ibm.db2.jcc.DB2Xml out_xml = null; 
 com.ibm.db2.jcc.DB2Xml inout_xml = xmlvar; 
 Connection con; 
 // 获取连接
……
 // 创建一个包含 XML 类型参数的 SQL 存储过程
 Statement stmt = con.createStatement(); 
 stmt.executeUpdate( “ create procedure SP_xml “ + 
	” (IN var1 XML, OUT var2 XML, INOUT var3 XML) “ + 
	” language sql “ + 
	” MODIFIES SQL DATA “ + 
	” begin DECLARE c1 CURSOR FOR “ + 
	” select XMLCOL1, XMLCOL2 from XMLTABLE where rownum=2; “ + 
	” insert into XMLTABLE values (2, var1, var3, NULL); “ + 
	” open c1; “ + 
	” fetch c1 into var2, var3; “ + 
	” close c1; “ + 
	” end; ” ); 
 // 创建 CallableStatement 
 CallableStatement cstmt = con.prepareCall( “ CALL SP_xml(?, ?, ?) ” ); 
 cstmt.setObject(1, in_xml); 
 // 注册 XML 参数为 com.ibm.db2.jcc.DB2Types.XML 
 cstmt.registerOutParameter(2, com.ibm.db2.jcc.DB2Types.XML); 
 cstmt.registerOutParameter(3, com.ibm.db2.jcc.DB2Types.XML); 
 cstmt.executeUpdate(); 
 // 获取 Out Parameter 中的 XML 数据
 out_xml = (DB2Xml)cstmt.getObject(2); 
 String ut = out_xml.getString()

JDBC4.0 规范颁布后 JCC 驱动对 XML 的支持

JDBC4.0 规范中定义了与 XML 数据对应的数据类型接口,java.sql.SQLXML,允许将 XML 类型的数据库列映射成 SQLXML 对象,并定义了创建和使用 SQLXML 的接口。 JCC 驱动版本 4 全面支持了 JCBC4.0 规范中定义的 XML 方法,方便了 DB2 Java 应用开发人员。

SQLXML 接口定义

清单 7 中列出了 SQLXML 接口中定义的方法。


清单 7. SQLXML 接口定义
String getString() throws SQLException; 
 InputStream getBinaryStream() throws SQLException; 
 Reader getCharacterStream() throws SQLException; 
  T getSource(Class sourceClass) throws SQLException; 
 void setString(String value) throws SQLException; 
 OutputStream setBinaryStream() throws SQLException; 
 Writer setCharacterStream() throws SQLException; 
  T setResult(Class resultClass) throws SQLException; 
 void free() throws SQLException;

SQLXML 中的 setter 方法用来设置 XML 数据的内容,使用 getter 方法来获取从数据库中取出的 XML 数据内容。 SQLXML 对象将在当前事务范围内有效,除非调用 free() 方法来显式关闭。

创建 SQLXML 对象

JDBC4.0 规范在 Connection 接口中定义了创建 SQLXML 对象的工厂方法,JCC 驱动版本 4 中实现了这个方法。需要注意的是,通过这个方法创建出来的 SQLXML 对象是“空”的,其中并没有 XML 数据,需要通过 SQLXML 自身的 setter 方法去设置。

interface Connection{ 
……
 SQLXML createSQLXML() throws SQLException; 
……
 }

设置 SQLXML 对象

JDBC4.0 规范在 PreparedStatement 中增加了新的方法,setSQLXML 来向参数中设置 SQLXML 对象,同时 setObject 方法也可以接收 SQLXML 对象作为参数。

interface PreparedStatement{ 
……
 void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException; 
 void setObject(int parameterIndex, Object x) throws SQLException; 
 void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException; 
 void setObject(int parameterIndex, Object x, int targetSqlType, 
         int scaleOrLength) throws SQLException; 
……
 }

在清单 8 的例子中,我们使用 SQLXML 对象向 XMLTABLE 中插入一行数据。首先通过 Connection 的 createSQLXML 方法创建了三个 SQLXML 对象,接着使用 SQLXML 接口中定义的 setString,setBinaryStream 和 setCharacterStream 方法向 SQLXML 对象中写入 XML 数据,最后使用 PreparedStatement 的 setSQLXML 和 setObject 方法将 SQLXML 对象与参数绑定。


清单 8. 使用 SQLXML 对象向 XMLTABLE 中插入一行数据
Connection con;
//获取 Connection
……
//创建三个 SQLXML 对象
SQLXML xmlObj1 = con.createSQLXML();
SQLXML xmlObj2 = con.createSQLXML();
SQLXML xmlObj3 = con.createSQLXML();
		
FileReader file = null;
BufferedReader br = null;
BufferedInputStream bis = null;
String xmlString = "";
		
try {
	//从文件 testfile1.xml 中读取数据
	file = new FileReader("C:\\work\\temp\\testfile1.xml");
	br = new BufferedReader(file);
	String line = null;
	while ((line = br.readLine()) != null) {
		xmlString += line;
	}
	//使用 setString 设置 xmlObj1 的内容
	xmlObj1.setString(xmlString);
	} catch (java.io.IOException e) {);
//获取 SQLXML 对象的字符输出流
Writer w = xmlObj2.setCharacterStream();
try {
	//从文件 testfile2.xml 中读取数据,同从文件 testfile1.xml 中读取数据
	……
//将 String 转化成字符流,再写入 Writer 中
   w.write(xmlString.toCharArray());
} catch (java.io.IOException e) {}
//获取 SQLXML 对象的字节输入流
OutputStream is = xmlObj3.setBinaryStream();
try {
	//从文件 testfile3.xml 中读取数据,同从文件 testfile1.xml 中读取数据
	……
	//将 String 转化成字节流,再写入 OutputStream 中
	is.write(xmlString.getBytes());
} catch (java.io.IOException e) {}		
PreparedStatement pstat = con.prepareStatement("INSERT INTO XMLTABLE " + 
	"(ROWNUM, XMLCOL1, XMLCOL2,XMLCOL3) VALUES (?,?,?,?)");
pstat.setInt(1, 1);
pstat.setSQLXML(2, xmlObj1);
pstat.setSQLXML(3, xmlObj1);
pstat.setObject(4, xmlObj1, java.sql.Types.SQLXML);
pstat.execute();

在这里有一点需要注意,在向 SQLXML 对象中写内容时,如果 SQLXML 对象已经被初始化,在调用 setter 方法会抛出 SQLException 。如果对 SQLXML 对象多次调用 setter 方法,也会抛出 SQLException,同时以前打开的 javax.xml.transform.Result, Writer 或者 OutputStream 也不再有效。

获取 SQLXML 对象

在 JCC 驱动版本 4 中,ResultSet 中增加了一个新的方法,getSQLXML,来获取 SQLXML 对象,原来的 getObject 方法现在也返回 SQLXML 对象,DB2Xml 不再推荐使用。

interface ResultSet { 
……
 SQLXML getSQLXML(int columnIndex) throws SQLException; 
 Object getObject(int columnIndex) throws SQLException; 
……
 }

在清单 9 的代码中,我们从 XMLTABLE 中查寻一行数据,并使用 ResultSet 的 getSQLXML 和 getObject 方法,以 SQLXML 对象的形式获取当前行中的 XML 数据,之后又通过 SQLXML 中定义的 getter 方法,取出 XML 数据的内容。


清单 9. 从 XMLTABLE 中查寻一行数据
Connection con;
//获取连接
……
PreparedStatement pstat = con.prepareStatement(
"SELECT XMLCOL1,XMLCOL2, XMLCOL3 FROM DB2ADMIN.XMLTABLE WHERE ROWNUM = ?");
pstat.setInt(1, 1);
ResultSet rs = pstat.executeQuery();
rs.next();
//通过 getSQLXML 获取 SQLXML 对象
java.sql.SQLXML xmlobj = rs.getSQLXML("XMLCOL1");
java.sql.SQLXML xmlobj2 = rs.getSQLXML("XMLCOL2");
//通过 getObject 获取对象后转换成 SQLXML 实例
java.sql.SQLXML xmlobj3 = (java.sql.SQLXML) rs.getObject("XMLCOL3");
//使用 SQLXM L的 getter 方法获取 XML 数据内容
java.io.InputStream isstream = xmlobj.getBinaryStream();
java.io.Reader xmlReader = xmlobj2.getCharacterStream();
String verifyString = xmlobj3.getString();

//SQLXML 的 getBinaryStream 方法返回的 InputStream 和 getCharacterStream 方法返回的 Reader 
//可以用作 Java 中XML Parser的参数,用来构建Document对象。
javax.xml.parsers.DocumentBuilder parser =
javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = parser.parse(binaryStream);

//SQLXML 的 getResource 方法返回 javax.xml.transform.Source 对象,
//这个对象可以用作 XML Parser 和 XSLT Transformer 的参数。
Transformer identity = TransformerFactory.newInstance().newTransformer();
Source source = sqlxml.getSource(null);
File myFile = new File("result.xml");
Result result = new StreamResult(myFile);
identity.transform(source, result);

动态更新 SQLXML 对象

在 JCC 版本 4 中定义了在可更新的结果集中动态更新 XML 数据列的方法,updateSQLXML,可以用来修改结果集中的当前行中的 XML 数据列,也可以向数据集中插入新的列。

interface ResultSet{ 
……
 void updateSQLXML(int columnIndex, SQLXML x) throws SQLException; 
……
 }

在清单 10 的代码中,我们创建了一个可更新的结果集,并使用 updateSQLXML 来更新当前列。


清单 10. 创建了一个可更新的结果集
SQLXML sqlXmlObj = con.createSQLXML(); 
 // 初始化 sqlXmlObj 
……
 PreparedStatement pstat = con.prepareStatement("SELECT XMLCOL1," 
+ "XMLCOL2, XMLCOL3 FROM DB2ADMIN.XMLTABLE WHERE ROWNUM = ?", 
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); 
 pstat.setInt(1, 1); ResultSet rs = pstat.executeQuery(); 
 rs.next(); 
 rs.updateSQLXML("XMLCOL1", sqlXmlObj); 
 rs.updateRow();


在存储过程中使用 SQLXML 对象

在存储过程或者用户自定义函数中都可以使用 SQLXML 作为参数,在使用 SQLXML 作为输出参数时,需要把参数类型注册为 java.sql.Types.SQLXML 。在设置 XML 类型的参数时,CallableStatement 提供了新的接口 setSQLXML 来设置 SQLXML 对象。当存储过程执行完毕后,可以通过 CallableStatement 的新接口 getSQLXML 来获得输出参数中的 XML 数据。

清单 11 中的代码调用了一个有三 XML 类型参数的存储过程,一个输入参数,一个输出参数,一个输入 / 输出参数。


清单 11. 调用存储过程
Connection con; 
 // 获取连接
……
 SQLXML in_xml = con.createSQLXML(); 
 SQLXML out_xml = null; 
 SQLXML inout_xml = con.createSQLXML(); 
 // 初始化两个 SQLXML 对象,in_xml 和 inout_xml 
……
 // 创建存储过程见清单 6 
……
 // 创建 CallableStatement 
 CallableStatement cstmt = con.prepareCall( “ CALL SP_xml(?, ?, ?) ” ); 
 cstmt.setObject(1, in_xml); 
 // 注册 XML 参数为
 cstmt.registerOutParameter(2, java.sql.Types.SQLXML); 
 cstmt.registerOutParameter(3, java.sql.Types.SQLXML); 
 cstmt.executeUpdate(); 
 // 获取 Out Parameter 中的 XML 数据
 out_xml = cstmt.getSQLXML(2); 
 inout_xml = cstmt.getSQLXML(3); 
 String ut = out_xml.getString() 
 String inout = inout_xml.getString();


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/15082138/viewspace-590676/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2008-08-05

  • 博文量
    269
  • 访问量
    555749