在JDBC4.0推出后,它的从多的特性正在受到广泛地关注。而最重要的更新就是支持XML数据类型(在最新的SQL2003标准中定义了这种数据类型),当然,将XML数据保存在数据库中,并在应用程序中更新XML数据并不是什么新技术。但这是JDBC第一次提供了一个映射接口(java.sql.SQLXML),并利用这个接口来支持SQL/XML数据类型。当然,为了满足处理XML数据类型的需要,其他的接口,如java.sql.Connection和java.sql.ResultSet,也被更新了。

在SQL2003标准和XML数据类型推出之前,开发人员必须将XML数据保存在BLOB、CLOB或TEXT类型字段中。现在,很多主流的数据库(如SQL Server、Oracle和DB2)已经加入了对XML数据类型的支持。但在JDBC4以前,Java应用程序仍然必须将数据库中的XML数据类型转换为JDBC支持的数据类型。但新的JDBC可以通过本地的接口来绑定XML,因此,在处理任何数据库中的XML数据变得更容易和高效。

在本文中将介绍如何用JDBC4.0来操作XML类型的字段(保存和获得XML数据),并给出了一个例子供读者参考。

一、存储和获得XML数据

为了将XML数据保存在一个XML类型的字段中,我们首先应该调用java.sql.Connection.createSQLXML()方法。这个方法返回了一个java.sql.SQLXML的实例。然后我们可以通过调用setOutputStream(), setCharacterStream()或简单地调用setString(String xml)来将XML数据加到SQLXML对象中。要注意的这个功能非常类似于BLOB和CLOB类型的使用。

JDBC4.0的关键特性之一就是我们还可以通过调用java.sql.SQLXML的setResult(Class resultClass)方法来获得一个设置avax.xml.transform.Result的类的实现。这些类包括DOMResult, JAXBResult以及SAXResult。换句话说,我们无需转换就可以简单地做以下事情:

1. 得到XML数据

2. 建立一个独立的DOMResult对象

3. 将DOMResult传入java.sql.SQLXML对象

4. 直接通过java.sql.Statement将XML数据保存到响应数据库字段中

为了java.sql.ResultSet获得SQLXML类型数据,我们只需要地调用getSQLXML,并指定相应地字段名或索引即可。然后我们可以通过getBinaryStream(), getCharacterStream()或getString()从java.io.InputStream中获得实际的XML数据,或是一个简单的字符串。保存XML数据也获得XML数据的过程类似,我们还可以通过调用SQLXML对象实例的getSource(Class sourceClass)方法来获得XML源,因此,我们可以从任何实现javax.xml.transform.Source的类访问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 =

"

"+


""+

"John Smith"+

"A very short article."+

"

";


static final String XML2 =

"

"+


""+

"Mary Jones"+

"Another short article."+

"

";


static final String XML3 =

"

"+


""+

"John Smith"+

"Last short 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表达式。由于XMLEXISTS和XMLQUERY函数所涉及的内容已经超出了本文的范畴,因此,本文并不涉及这些内容,感兴趣的读者可以参考其他的相关文档。

三、更广泛地应用

使数据库支持SQL/XML可以改善代码的透明度,也可以大幅度地缩短开发周期。在一般情况下,也许都会有一些不得以的原因将XML数据保存在数据库中。这些原因也许是使用最通常的方法来演示在线媒体数据,如文档、事件列表,或产品信息,为了将实体数据保存成XML,并将这些XML数据转换成可以显示的形式。java.sql.SQLXML API文档为我们提供了很多小例子来演示如何做这些工作,有些例子也在Java SE6的文档中列出,如下面的代码:

File xsltFile = new File("transformer.xslt");

File xhtmlFile = new File("xhtml.xml");

Transformer xslt =

TransformerFactory.newInstance().newTransformer(new

StreamSource(xsltFile));

Source source = sqlxml.getSource(null);

Result result = new StreamResult(xhtmlFile);

xslt.transform(source, result);

上面代码的sqlxml变量是一个从数据库中获得的java.sql.SQLXML实例。本质上,我们可以将XML数据转换为XHTML形式,上面的几行简单的代码完成了这项工作。

QQ 744437114

疯狂软件官网:http://www.fkjava.org

疯狂java视频 android视频:http://www.fkjava.org/video.html