Lập trình với XML cho DB2, Phần 2: Phát huy sự hỗ trợ của
cơ sở dữ liệu cho XML trong kiến trúc ứng dụng của bạn
Giới thiệu
Vị thế của XML trong cơ sở dữ liệu đã thay đổi trong vài năm qua, từ một công nhân tạm thời
thành một công dân hạng nhất. Nó không còn phải biến hình nhân dạng để phù hợp với thế giới
dữ liệu quan hệ. Nó duy trì các di sản phân cấp của nó một cách tự hào, ngay cả khi khai thác sức
mạnh và sự ổn định của thế giới cơ sở dữ liệu quan hệ. Thực vậy, một số láng giềng cơ sở dữ liệu
quan hệ của nó phải có các kỹ thuật thích nghi, làm cho mình giống với XML để khai thác sự
phong phú của mô hình XML phân cấp.
Bài viết này giới thiệu cách môi trường lưu trữ và truy vấn XML mới làm việc trong mô hình dữ
liệu XML từ phần 1. Nó cho thấy rằng một khi bạn thích ứng với kiến trúc phát triển ứng dụng
dựa trên XML mới, thì các lược đồ cơ sở dữ liệu của bạn trở nên đơn giản hơn nhiều và tự nhiên
hơn như thế nào. Nó cũng cho thấy cách truy vấn dữ liệu XML trong cơ sở dữ liệu không khác
với cách truy vấn dữ liệu trong ứng dụng. Cuối cùng, nó cho bạn thấy cách kết hợp các dữ liệu
quan hệ với các dữ liệu XML để có được những điểm tốt nhất của cả hai thế giới đó.
Về đầu trang
Các khái niệm cơ bản về cơ sở dữ liệu XML
Mặc dù hầu hết các cơ sở dữ liệu quan hệ chính đều có một số hỗ trợ cho XML, nhưng sự hỗ trợ
của pureXML DB2 cho XML là mạnh mẽ và hiệu quả hơn nhiều, làm cho nó trở thành một cơ sở
dữ liệu lý tưởng để thử nghiệm mô hình lập trình XML. Trong bài này tôi tập trung vào cách để
khai thác sự hỗ trợ đã cải tiến này của cơ sở dữ liệu cho XML trong kiến trúc ứng dụng của bạn.
DB2 cho phép bạn lưu trữ, truy vấn, thao tác và xuất bản:
Dữ liệu quan hệ bằng SQL
Dữ liệu quan hệ như XML bằng SQL/XML
Dữ liệu XML bằng Xquery
Dữ liệu lai (Dữ liệu quan hệ & XML) bằng SQL/XML và Xquery
Hình 1. Lưu trữ lai của DB2
Lưu trữ XML trong cơ sở dữ liệu
Ưu điểm chính của sự hỗ trợ XML trong cơ sở dữ liệu quan hệ là bạn có thể ghi lưu được cả dữ
Liệt kê 2. Chèn vào từ một chương trình Java
String insertsql= "insert into PURCHASE_TABLE values(?,?)";
PreparedStatement iStmt=connection.prepareStatement(insertsql);
File inputfile= new File(filename); //filename is the path of the XML file
long filesize=inputfile.length();
BufferedReader in = new BufferedReader(new FileReader(inputfile));
iStmt.setCharacterStream(1,in,(int)filesize);
int rc= iStmt.executeUpdate();
Để hiểu rõ hơn về lưu trữ lai, bạn hãy nhìn vào khung nhìn về cách dữ liệu XML dường như về
lôgic được lưu giữ như thế nào trong cơ sở dữ liệu quan hệ.
Ghi chú: Ngay cả khi công nghệ lưu trữ vật lý cho XML có thể khác nhau với từng nhà cung cấp
cơ sở dữ liệu quan hệ khác nhau, thì khung nhìn lôgic là như nhau.
Hình 2. Khung nhìn lôgic lưu trữ lai của DB2
Truy vấn XML
Khi mở rộng mô hình lược đồ cơ sở dữ liệu thì bạn có thể thấy các bảng quan hệ và các cột. Nếu
bạn đào sâu vào một cột XML, thì lược đồ chuyển từ mô hình quan hệ sang mô hình phân cấp
cho XML. Bây giờ, nếu bạn bỏ qua thực tế là có hai lược đồ: lược đồ quan hệ và lược đồ XML,
và chỉ coi chúng là một mà thôi, thì sau đó bạn có thể điều hướng và truy vấn vào lược đồ thống
nhất một cách tự nhiên hơn.
Trong lược đồ thống nhất trong Liệt kê 1, nếu bạn muốn lấy dữ liệu trong cột CUSTXML của
CUSTOMER_TABLE, thì bạn phải xác định đường dẫn đến cột CUSTXML làm đích trong truy
vấn của bạn.
SELECT CUSTXML FROM CUSTOMER_TABLE where customerid='hardeep';
Truy vấn này trả về dữ liệu khách hàng bên trong cột CUSTXML có tên là Hardeep.
Bây giờ hãy xem xét trường hợp bạn muốn dữ liệu khách hàng có họ (lastname) là Singh. Trong
where xmlexists ('$CUSTXML/Customer[@lastname= $lname ]'
passing cast(? as VARCHAR(12)) as "lname")
Về đầu trang
Đẩy logic ứng dụng sang cơ sở dữ liệu
XQuery có tất cả các chức năng thô sơ của hầu hết các ngôn ngữ bậc cao (các câu lệnh if-then-
else, for, các biến, các hàm và các toán tử số học). Điều này làm cho có thể nhúng logic nghiệp
vụ bên trong truy vấn. Thêm nữa, nó có rất nhiều chức năng chung ánh xạ đến XSLT làm cho có
thể không chỉ truy vấn mà còn biến đổi đầu ra XML ngay trong cơ sở dữ liệu.
Hãy lấy ví dụ Customer cho mô hình dữ liệu XML từ phần 1.
<Customer customerid ="" firstname="" lastname="" >
<Items><Item ID="" description="" purchaseDate="" price="" /></Items>
</Customer>
Thay thế mã ứng dụng bằng truy vấn DB2
Thay vì việc hợp nhất các dữ liệu XML từ hai bảng trong tầng ứng dụng, bạn có thể làm điều
tương tự trong cơ sở dữ liệu bằng cách sử dụng một truy vấn SQL/XML đơn lẻ. Một phép nối
một - nhiều của CUSTOMER_TABLE.CUSTXML/Customer/@customerid với
PURCHASE_TABLE.ITEMXML/Customer/@customerid.
Hình 3. Phép nối hai cột XML Liệt kê 3. Truy vấn hai cột XML
values(xmlquery('
for $Customer in db2-fn:xmlcolumn( "CUSTOMER_TABLE.CUSTXML")/Customer
where $Customer/@customerid= $customerid
where $Customer0/@customerid= $Customer/@customerid
return $Customer0/Item
}</Items>)
where $Customer/@customerid= $customerid
return
transform
copy $cust:=$Customer
modify(
do insert $items as last into $cust)
return $cust
' passing hardeep as "customerid" ))
Trong các truy vấn trên, bạn không chỉ tìm kiếm, lấy ra và hợp nhất các bộ phận của tài liệu
XML được lưu trữ trong cơ sở dữ liệu, mà bạn cũng đã biến đổi kết quả XML bằng cách thêm
các phần tử mới vào cho nó. Ngoài ra, phần tử hardeep đã được ngầm ép kiểu thành kiểu (xs:
string) của XML.
So sánh giữa truy vấn cơ sở dữ liệu và mã ứng dụng Java
Nếu bạn so sánh các truy vấn ở trên với mã Java (Liệt kê 6. Viết lại ứng dụng để sử dụng mô
hình XML) trong phần 1, bạn sẽ thấy rằng logic là khá tương tự.
1. Chọn các thông tin Customer từ CUSTOMER_TABLE.
2. Xây dựng phần tử Items và tìm tất cả các mục mà khách hàng đó đã mua từ
PURCHASE_TABLE.
3. Lặp lại từng mục trong danh sách đã chọn và chèn nó vào phần tử Items.
4. Chèn phần tử Items vào phần tử Customer.
Tạo một thủ tục lưu sẵn
Để tách logic nghiệp vụ trong cơ sở dữ liệu khỏi mã ứng dụng, một ý tưởng tốt là tạo ra một thủ
' passing custid as "customerid" ))
OPEN c_cur;
END
Thay thế mã ứng dụng bằng cách gọi ra thủ tục lưu sẵn
Mã ứng dụng bây giờ gọi thủ tục lưu sẵn của DB2 và chuyển XML đến lớp bao gói DOM. Mã
ứng dụng cho mô hình XML trong phần 1 (Liệt kê 6. Viết lại ứng dụng để sử dụng mô hình
XML dòng 2 đến 8) sẽ rút lại thành:
2. ResultSet dbResult = dbstmt.executeQuery("call customerItems
("+custid+")"
3. XMLParse customerXML = new XMLParse(dbResult. getString(1));
Về đầu trang
Một ví dụ phức tạp hơn
Ta hãy xem xét một kịch bản phức tạp hơn một chút, kịch bản này cũng tính toán số tiền bảo
hiểm trên mỗi mục hàng. Để cho thành khó khăn hơn một chút, số tiền bảo hiểm không chỉ thay
đổi hàng ngày mà còn thay đổi theo giá cả. Điều này có nghĩa là bạn phải chuyển đến truy vấn
không chỉ là customerid mà còn cả mức giá bảo hiểm. Bây giờ giả sử rằng bạn truy vấn mức bảo
hiểm hàng ngày mới nhất từ trang Web dịch vụ được công ty bảo hiểm cung cấp. Các thông tin
về tỷ lệ bảo hiểm là một tài liệu XML.
<insurance>
<rate price="100" currency="$" rate=".02"/>
<rate price="500" currency="$" rate=".018"/>
<rate price="" currency="$" rate=".015"/>
</insurance>
Bạn có thể sửa đổi thủ tục lưu sẵn ở trên để tính toán mức giá bảo hiểm.
Liệt kê 6. Thủ tục lưu sẵn tính toán tiền bảo hiểm cho mỗi mục hàng
CREATE PROCEDURE customerItemsWithInsurance(IN custid varchar(12), rate
)}</insurance>
where $Customer0/@customerid= $Customer/@customerid
return
transform
copy $item:=$Customer0/Item
modify( do insert $insurance as last into $item)
return $item
}</Items>
)
where $Customer/@customerid= $customerid
return
transform
copy $cust:=$Customer
modify(do insert $items as last into $cust)
return $cust
' passing custid as "customerid", rate as "rate" ));
OPEN c_cur;
END
Cuộc gọi đến thủ tục lưu sẵn có hai thông số thời gian chạy, customerid và phần tử XML
insurance.
call customerItemsWithInsurance(?,?)
Từ ví dụ trên ta thấy rõ ràng là nếu dữ liệu đang được thao tác trong cơ sở dữ liệu ở định dạng
liệu được lưu trữ trong cơ sở dữ liệu quan hệ." Truy vấn có thể được đơn giản hóa bằng
cách sử dụng hàm XMLROW mới, được đưa vào trong Viper 2.
Select XMLROW (customerid, firstname, lastname OPTION as attributes ROW
Customer)
from customer_table where customerid=?
Bạn cũng có thể tạo phép nối giữa dữ liệu quan hệ và dữ liệu XML. Trong kịch bản ví dụ,
nếu bạn đã có bảng thứ ba có chứa mô tả sản phẩm của các mục đã mua và đây là một
bảng quan hệ, thì bạn có thể lấy các mô tả sản phẩm đó cho từng mục đã mua bằng cách
thực hiện phép nối, sử dụng ID của mục hàng. Hình 5. Nối các cột quan hệ và XML
Select details, weight from SQLPRODUCT, ITEM_TABLE
where xmlexists ('$itemxml/item[@itemid=$pid]'
passing ITEM_TABLE.ITEMXML AS "itemxml", SQLPRODUCT.PID AS "pid" )
Trong DB2 phiên bản 9, bạn có thể chuyển các thông số thời gian chạy tới cho XQuery
được nhúng trong câu lệnh SQL bằng cách sử dụng mệnh đề passing nhưng bạn không
thể làm tương tự cho SQL được nhúng trong XQuery. Trong Viper 2, hạn chế này đã
được gỡ bỏ và bây giờ bạn có thể chuyển một biến thời gian chạy sang truy vấn quan hệ
được nhúng vào XQuery. Liệt kê 7. Chuyển biến thời gian chạy tới cho SQL nhúng trong XQuery
values(xmlquery('
for $Customer0 in db2-fn:xmlcolumn("PURCHASE_TABLE.ITEMXML")/Customer
XML là một ngôn ngữ tuyệt vời. Hầu hết các ngành nghề và các tổ chức chính phủ đang tiêu
chuẩn hóa các lược đồ XML của mình và yêu cầu làm việc với các văn bản điện tử phù hợp với
các lược đồ này. Vì dữ liệu giữa các doanh nghiệp (B2B) được trao đổi qua đường cáp mạng
hiện tại dưới dạng XML, thì tại sao lại không lưu trữ dữ liệu dưới dạng như nó vốn thế
(pureXML) trong cơ sở dữ liệu? Một khi bạn lưu trữ dữ liệu dưới dạng XML, thì bạn có thể lập
chỉ mục, truy vấn, xác nhận, thao tác, biến đổi, và cập nhật nó bằng cách sử dụng XQuery và
SQL/XML tiêu chuẩn. Khi bạn đẩy nhiều logic ứng dụng hơn vào truy vấn, thì cơ sở dữ liệu của
bạn trở thành một bên tham gia tích cực trong thế giới kiến trúc hướng dịch vụ (SOA) bằng việc
xuất bản các thủ tục lưu sẵn của nó làm dịch vụ web và nguồn cấp dữ liệu.
"Trật tự cũ đã thay đổi, nhường chỗ cho cái mới." Tác giả: Morte d'Arthur