程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 使用JDBC4.0操作XML類型數據

使用JDBC4.0操作XML類型數據

編輯:關於JAVA

在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 =
"<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表達式。由於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形式,上面的幾行簡單的代碼完成了這項工作。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved