Open-Source World

          let's learn and study.
          posts - 28, comments - 23, trackbacks - 0, articles - 1

          Derby入門 —— (2)

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

          Feedback

          # re: Derby入門 —— (2)   回復(fù)  更多評(píng)論   

          2008-04-27 17:34 by arzhuo
          文章非常好,能將這個(gè)Derby這篇文章有關(guān)的源碼發(fā)給我嗎,謝謝!
          我的郵箱是: arzhuo@gmail.com

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 东台市| 呼伦贝尔市| 仙居县| 和顺县| 阳东县| 天津市| 新晃| 专栏| 牟定县| 双桥区| 玉山县| 湖州市| 卢龙县| 桑日县| 濮阳县| 富锦市| 溧阳市| 察雅县| 晋江市| 中宁县| 洱源县| 建宁县| 景洪市| 高平市| 泸西县| 高雄市| 漠河县| 永川市| 靖远县| 海阳市| 东乡县| 泉州市| 梨树县| 朝阳县| 瑞金市| 闽侯县| 吉林市| 昂仁县| 平舆县| 长春市| 张北县|