自動層疊刪除
現在你有超過一萬條的定單數據,你需要保證這些在數據庫里的數據沒有被破壞。固定這些數據是毫無疑問的。
讓我舉例說明一個潛在的問題,這個問題的中心是圍繞在刪除一個顧客后。問題就有可能會出現。
使用標準的SQL語句,只從custs表中刪除顧客信息:
delete from custs where id='838';
這是從數據庫中刪除顧客編號為838的消費者。好極了!
如果這是你所做的,數據庫的數據正式被破壞了。為什么呢?這是因為在數據庫里有10定單信息沒有關聯到消費者!
這可能引起應用程序各種各樣的錯誤。所有應用程序取得定單信息并嘗試打印顧客信息時,都會涉及到這個異常。當你列出所有用戶和他們的定單信息時,有些定單信息永遠都不會顯示出來。
在關系數據庫管理系統的條款中,數據庫引用完整性是不允許這樣的情況的。這是因為一條顧客記錄被刪除,而沒有刪除相應的定單信息。
因此,我們需要這樣做:
delete from custs where id='838';
delete from orders where custid='838';
而且,我們需要確保兩條刪除命令在同一個事務中執行。要么兩條語句都執行成功,要么都執行失敗。
這個稱為刪除層疊,因為刪除顧客記錄導致刪除定單信息。
Derby有能力處理引用完整性。
Derby觸發器
保證引用完整性的方法是定義一個觸發器。一個觸發器是一段代碼或SQL語句,當數據發生修改或存取時,它將在數據庫服務器里執行。Derby支持定義觸發器(使用SQL語句或Java代碼),當顧客記錄被刪除時,可以編碼實現刪除關聯的定單信息。然而,在Derby里有一個更簡單的方法。
它可以告訴Derby,使用標準的SQL DDL(數據定義)語句,這涉及到orders表和custs表。你也可以告訴Derby去完成自動層疊刪除。
添加參考約束
要添加自動層疊刪除,就要修改原始的createdb.sql里的語句。在db\ref子目錄下找到createdbref.sql文件。你需要對orders表定義進行修改。添加下面蘭色字體的內容:
create table orders
(id char(8) not null,
custid char(5) not null
references custs (id) on delete
cascade, total integer,
primary key(id,custid));
另外一個不同是連接數據庫的URL值。這時,網絡驅動器是指定的。一定要注意網絡驅動器是需要用戶名和密碼的,默認的用戶名和密碼都是APP,所以URL值將修改為:
connect 'jdbc:derby:net://localhost/
vsjdb:user=APP;password=APP;';
你現在可以強行創建帶參考約束的新表。確保復制createdbref.sql到你的工作目錄。再次啟動ij。現在,使用下面的命令可以刪除所有記錄并創建新表:
run 'createdbref.sql';
在創建了表后,你可以再次運行TableFiller.java文件去在表中添加10000條定單數據。使用network子目錄的修改版本。在原始的TableFiller.java里修改的部分如下面蘭色字體顯示的:內容:
import java.sql.*;
import java.util.Properties;
public class TableFiller {
Connection conn = null;
PreparedStatement insertCust
= null;
PreparedStatement insertOrder
= null;
String driverName=
“com.ibm.db2.jcc.DB2Driver”;
String url =
“jdbc:derby:net://localhost/
vsjdb:user=APP;password=APP;”;
...
裝載的驅動器將要改為網絡驅動器(com.ibm.db2.jcc.DBDriver),URL值最好還是改成訪問網絡JDBC驅動器的值。否則,這個代碼將與原始的TableFill.java文件一樣。如果你要寫你自己的JDBC代碼,你可以設置一個string從外部文本文件里讀取參數,這樣你將不需要修改代碼就能在嵌入式關系數據庫管理系統和網絡關系數據庫管理系統之間轉換。
多用戶并發訪問
現在,來關注多用戶連接,在另一個控制臺窗口啟動ij會話,并連接到服務器使用下面的命令:
connect 'jdbc:derby:net://localhost/
vsjdb:user=APP;password=APP;';
在原始的控制臺窗口,編譯并運行新的TableFiller.java文件。這將創建1000個顧客記錄和10000條定單記錄。當這些操作執行完畢后,回到新的ij窗口并使用下面的命令:
select * from custs;
…and:
select * from orders;
當你執行這個命令的時候,你將發現所有用戶和定單信息都已經被創建。網絡服務器允許多用戶并發訪問數據。
測試層疊刪除
一旦你創建了數據記錄,試著在ij里執行下面的語句:
select * from custs where id='700';
接著執行下面的語句:
select * from orders where
custid='700';
你將看到顧客記錄和這個顧客的10條定單信息。
現在,嘗試刪除顧客,使用下面的命令:
delete from custs where id='700';
這將刪除用戶記錄,層疊將會刪除關聯的定單信息?,F在嘗試再次使用上面的select語句查看,你將發現那10條定單信息也被刪除了。
寫一個Derby存儲過程
在實驗的最后,你將用Java編程語言創建一個Derby存儲過程。你也可以存儲代碼到存儲過程進入Derby數據庫內部,Derby能輕松的區分數據和代碼。
該存儲過程將調用deleteAll(),從它的名字可以理解到,它將刪除數據庫里的所有記錄。在stored子目錄下可以找到實現該存儲過程的Java代碼,它的名字為CleanTables.java。代碼內容如下:
import java.sql.*;
public class CleanTables {
public static void delAll ()
throws SQLException {
Connection conn =
DriverManager.getConnection(
"jdbc:default:connection");
Statement delCusts =
conn.createStatement();
delCusts.executeUpdate(
"delete from custs");
delCusts.close();
conn.close();
return;
}
}
你可以看到,該存儲程序在Java類里是一個public static的方法。JDBC連接器的內容是代碼里url的值:
jdbc:default:connection
這會告訴Derby服務器提供一個默認的連接到代碼。Derby將管理這些連接。實際上的語句是執行:
delete from custs;
自從層疊刪除生效,刪除custs表的任何數據,也將刪除orders表里相關聯的數據。
在Derby數據庫里存儲Java代碼
要在Derby數據庫里存入Java代碼,你首先需要編譯該代碼并創建成JAR文件。編譯CleanTables.java代碼:
javac CleanTables.java
創建JAR文件:
jar cvf vsjstproc.jar *.class
或者你可以使用makejar.bat文件來完成上述操作,復制生成的vsjstporc.jar文件到工作目錄。
在工作目錄,你需要設置該JAR文件到數據庫中。在ij中使用下面的命令(確保你的連接會話是通過網絡驅動器獲得的):
call sqlj.install_jar('vsjstproc.jar',
'APP.cleanTable', 0);
這個命令實際上是調用一個存儲過程,它將設置vsjstporc.jar文件到數據庫并為它設置是內部名cleanTable。APP引用應用程序計劃。讓JAR文件在數據庫里是非常方便的。當你復制數據庫時,這些代碼將跟著被移動。
如果你需要從數據庫里刪除該JAR文件,你可以使用:
call sqlj.remove_jar(
'APP.cleanTable', 0);
在刪除調用中僅僅需要內部名。
當把JAR設置到數據庫里后,當它需要讀取Java代碼時,你需要告訴Derby去識別該JAR文件。這些都需要通過存儲過程設置一個屬性:
call syscs_util.syscs_set_database_
property('derby.database.
classpath', 'APP.cleanTable');
當裝載Java類時,Derby都會查看內部的APP.cleanTable JAR文件。你最后準備定義一個名為deleteAll()的存儲過程。使用下面的命令:
create procedure deleteAll() parameter
style java language java modifies
sql data external name
'CleanTables.delAll';
Derby將從APP.cleanTable JAR文件找到CleanTable類,并鎖定該類的static delAll()方法。如果你需要刪除該存儲過程,你可以使用下面的命令:
drop procedure deleteAll;
有了該存儲過程,你可以刪除這兩個表的所有數據,只需要簡單的在ij下調用存儲過程deleteAll():
call deleteAll();
在這個存儲過程執行完畢后,你將發現這兩個表是空的了。
結論
Derby是一個具有豐富特性的關系數據庫系統,并能集成到你的項目中。
它支持嵌入式模式和客戶端-服務器模式操作,它能適應部署多變的情況。它是100%用Java實現的,并與你的Java應用程序一樣的享受‘隨時發布’。它能快速執行和處理大量數據,同時也支持高級特性,例如引用完整性和存儲項目,它以達到理想化的持久化的數據存儲所必須的。最后但并不是最小,它自由的Apache許可讓你自由的綁定它到你的產品中。
開源像礦山有很多隱藏的寶石一樣。如果你沒有再次關注Apache Derby,你將不會注意到有鉆石的存在。
關于作者:
Sing Li:顧問,培訓師和自由作家,他專攻Java,web應用程序,分布式計算和對等技術。他的最近出版包括Early Adopter JXTA,Perfessional JINI和Professional Apache Tomcat,這些都是Wrox出版社出版
下載和安裝Derby
一旦你解壓下載的Derby,注意你的解壓目錄,這是你的Derby安裝目錄。你需要使用這個目錄去設置的你的classpath。
下載Derby JDBC的網絡驅動器
為了在網絡模式下訪問Derby,你將需要一個JDBC網絡驅動器。IBM捐贈了這個驅動器給Derby項目,但是直到寫本文時,它都不是一個標準版本。
暫時,你將需要下載IBM DB2 JDBC Universal driver for Apache Derby Network Server。根據地址里的說明去設置你的classpath。