技术开发 频道

使用JDBC4.0操作XML类型数据



二、实例程序
 
    由于JDBC4是在2006年12月11日由官方发布的(随J2SE6.0发布),因此,现在很多数据库驱动对JDBC4支持的还不是很好。在本例子中使用了Apache Derby数据库的较版本10.2来讨论对XML类型数据的保存和获取。Derby的这个版本还不持java.sql.SQLXML,这就意味着我们不能直接从结果值中获得XML数据,以及绑定XML数据。但Derby和SQL 2003兼容,可以常非容易地使用嵌入模式,类此,它仍然可以为我们演示如何操作XML数据,就好象在使用一个完全支持JDBC4的驱动一样。用于操作Derby的XML数据的代码如下:

import java.io.StringReader; import java.sql.*; public class XmlDbTester { static final String XML1 = "<article>"+ "<title>First Article</title>"+ "<author>John Smith</author>"+ "<body>A very short article.</body>"+ "</article>"; static final String XML2 = "<article>"+ "<title>Second Article</title>"+ "<author>Mary Jones</author>"+ "<body>Another short article.</body>"+ "</article>"; static final String XML3 = "<article>"+ "<title>Third Article</title>"+ "<author>John Smith</author>"+ "<body>Last short article.</body>"+ "</article>"; static final String[] ARTICLES = {XML1, XML2, XML3}; public static void main(String s[]) { XmlDbTester xdt = new XmlDbTester(); Connection c = xdt.getConnection(); xdt.loadDemoData(c); xdt.demoXmlResult(c); xdt.demoXPath(c); xdt.closeConnection(c); System.out.println("Done"); System.exit(0); } void demoXmlResult(Connection c) { try { Statement s = c.createStatement(); ResultSet rs = s.executeQuery("SELECT XMLSERIALIZE (DATA AS CLOB) "+ "FROM ARTICLE WHERE ID = 2"); while(rs.next()) System.out.println("The article XML for article with ID = 2: \n"+ rs.getString(1)); s.close(); rs.close(); } catch(Exception e) { e.printStackTrace(); } } void demoXPath(Connection c) { try { Statement s = c.createStatement(); ResultSet rs = s.executeQuery("SELECT ID FROM ARTICLE WHERE "+ "XMLEXISTS('//author[text()=\"John Smith\"]' PASSING BY REF "+ "DATA)"); while(rs.next()) System.out.println("John Smith wrote article with ID: "+ rs.getInt(1)); s.close(); rs.close(); } catch(Exception e) { e.printStackTrace(); } } void loadDemoData(Connection c) { try { Statement s = c.createStatement(); s.execute("CREATE TABLE ARTICLE(ID INTEGER, DATA XML)"); System.out.println("Created demo table: ARTICLE"); s.close(); PreparedStatement ps = null; int id = 1; for(String insert : ARTICLES) { ps = c.prepareStatement("INSERT INTO ARTICLE (ID, DATA) VALUES "+ "(?, XMLPARSE (DOCUMENT CAST (? AS CLOB) PRESERVE "+ "WHITESPACE))"); ps.setInt(1, id++); ps.setClob(2, new StringReader(insert)); ps.executeUpdate(); } System.out.println("Inserted test data into ARTICLE"); if(ps != null ) ps.close(); } catch(SQLException e) { e.printStackTrace(); } } Connection getConnection() { Connection c = null; try { c = DriverManager.getConnection("jdbc:derby:XmlDemo;create=true"); c.setAutoCommit(false); } catch (Exception e) { e.printStackTrace(); } return c; } void closeConnection(Connection c) { try { c.close(); } catch(Exception e) {} } }
    Derby数据库中存在很多专门针对XML的操作符,如XMLPARSE和XMLSERIALIZE,它们将帮助我们将数据转换为字符数据流或字符串,以便我们在程序中使用。在调用这些语句之后,将是我们例子中的具体要完成的任务。在这里,我还会介绍如使用和SQL/XML完全兼容的JDBC驱动来完成这些任务。事实上,我们可以完全使用java.sql.SQLXML来实现这个例子,这样做虽然会编译通过,但程序运行的结果会抛出一个Derby-specific异常,如"Binding directly to an XML value is not allowed."。总之,本例的代码只是为了演示程序如何也SQL/XML兼容性数据库交互。下面我将分别讲解一下重要的代码片段。

    在上面的例子代码中,首先建立一个简单的数据表,这个数据表包含一个XML类型的数据字段DATA,代码如下:

Statement s = c.createStatement(); s.execute("CREATE TABLE ARTICLE(ID INTEGER, DATA XML)");
    接下来向数据表中插入数据。由于目前Derby还不支持java.sql.SQLXML类型的数据,当我们在DATA插入数据时,必须将XML数据绑字到其它可以析XML数据的类型上。在这里我们使用CLOB类型,代码如下:

ps = c.prepareStatement("INSERT INTO ARTICLE (ID, DATA) VALUES "+ "(?, XMLPARSE (DOCUMENT CAST (? AS CLOB) PRESERVE "+ "WHITESPACE))"); ps.setInt(1, id++); ps.setClob(2, new StringReader(insert));
    现在,如果我们有一个和JDBC4完全兼容的驱动,也可以使用java.io.Writer来做同样的事,代码如下:

ps = c.prepareStatement("INSERT INTO ARTICLE (ID, DATA) values (?, ?)"); SQLXML article = c.createSQLXML(); Writer writer = article.setCharacterStream(); writer.write(insert); writer.close(); ps.setInt(1, id++); ps.setSQLXML(2, article);
    或使用javax.xml.transform.dom.DOMSource来完成这项工作:

ps = c.prepareStatement("INSERT INTO ARTICLE (ID, DATA) values (?, ?)"); SQLXML article = c.createSQLXML(); DOMResult dom = (DOMResult)article.setResult(DOMResult.class); dom.setNode(doc); // doc is instance of org.w3c.dom.Document ps.setInt(1, id++); ps.setSQLXML(2, article);
接下来我们来从数据库中获得XML数据。和插入数据类似,当我们从Derby中获得XML数据时,必须将XML数据类型转换成字符类型,代码如下:
 
ResultSet rs = s.executeQuery("SELECT XMLSERIALIZE (DATA AS CLOB) "+
   "FROM ARTICLE WHERE ID = 2");
 
    如果使用支持java.sql.SQLXML的驱动,我们可以通过直接使用XML数据库类型来完成类似的工作。也就是说我们可以直接得到XML数据。下面的代码假设我们使用DOM分析XML,并获得记录集:

PreparedStatement st = c.prepareStatement("SELECT ID, DATA FROM ARTICLE"); ResultSet rs = st.executeQuery(); while (rs.next()) { SQLXML article = rs.getSQLXML("DATA"); InputStream stream = article.getBinaryStream(); DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = parser.parse(stream); // Do something... }
在这种情况下无需使用getBinaryStream()方法,而取而代之的是getSource(Class sourceClass)方法,这个方法可以得到DOMSource、SAXSource或任何其他实现javax.xml.transform.Source的类实例。

下面我们来使用XPath来过滤XML数据。在这个例子的最后演示了如何在新版的SQL2003中使用XPath语句:XMLEXISTS来过滤数据。代码如下:
 
Statement s = c.createStatement();
ResultSet rs = s.executeQuery("SELECT ID FROM ARTICLE WHERE "+
   "XMLEXISTS('//author[text()=\"John Smith\"]' PASSING BY REF "+
   "DATA)");

   
注意,我们还可以使用XMLQUERY 函数来执行XQuery表达式。由于XMLEXISTSXMLQUERY函数所涉及的内容已经超出了本文的范畴,因此,本文并不涉及这些内容,感兴趣的读者可以参考其他的相关文档。
0
相关文章