解決存儲過程固有限制的方法之一就是將SQL嵌入到更加通用的語言中去。與存儲過程將業務邏輯移入數據庫相反,內聯SQL將SQL從數據庫移入了應用程序代碼。這就使得SQL語句能夠直接與語言進行交互。從某種意義上說,SQL成爲了該語言的一個特性。有不少語言具備這種「特 性」,包括COBOL、C、甚至Java。如下就是Java中SQL的一個示例:html
String name; Date hiredate; #sql { SELECT emp_name, hire_date ,hiredate FROM employee WHERE emp_num = 28959 };
內聯SQL的確很是優雅,由於它作到了與語言的緊密結合。本地語言變量能夠直接傳遞給 SQL做爲參數,SQL執行結果可直接賦值給相似的變量。某種意義上,SQL的確成爲了該語言的 一個特性。sql
但不幸的是,內聯SQL並無被普遍接受,一些重大問題的存在終於仍是使得它沒法開花結果。首先,SQL還不標準,它存在許多擴展版本,而每一個版本又都只適用於某個特定的數據庫。數據庫
SQL語言的分裂使得要實現一個既完備又可在各個數據庫平臺間移植的內聯SQL分析器很是困難。內聯SQL的第二個問題就是它每每並非真的實現爲語言的一個特性,而是使用一個預編譯 器先將內聯SQL 「翻譯」爲當前語言中的相應代碼。這就給像IDE (integrated development environment,集成開發環境)這樣的工具帶來了問題,由於這些工具可能須要預先解釋代碼以啓 用像語法突出顯示和代碼完成這樣的高級特性。而包含內聯SQL的代碼若是沒有預編譯器可能甚 至連編譯都沒法經過,這種依賴性使得人們不得不擔憂他們的代碼在未來的可維護性。編程
解決內聯SQL這些問題的方案之一就是將SQL從語言級移除,代之以應用程序中的某種數據結構(如字符串)來表現它。這種方法就是咱們一般所說的動態SQL (dynamic SQL)。緩存
動態SQL數據結構
動態SQL經過避免使用預編譯器來解決內聯SQL存在的一些問題。做爲替代,SQL被表現爲 一種字符串類型的數據,能夠像現代語言中全部其餘的字符數據同樣地操縱它。由於SQL被表示 爲種字符串類型,因此它就再不能像內聯SQL同樣直接與語言進行交互了。所以,動態SQL的實現須要一組強壯的API,用來設置SQL參數,獲取結果數據,等等。架構
動態SQL的優勢就在於其具備的靈活性。SQL能夠在運行時基於不一樣的參數或動態的應用程 序功能來構建。例如,一個「按樣例查詢(query-by-example)」的Web表單就可能容許用戶動態選擇須要搜索的字段,以及但願搜索的數據。這就要求SQL語句的WHERE子句可以動態改變,使 用動態SQL就很是容易作到這一點。框架
動態SQL是目前從現代編程語言訪問關係數據庫的方法中最流行的。大多數這樣的現代編程語言都包括用於進行數據庫訪問的標準API。相信Java開發人員和.NET開發人員對各自語言(分別是JDBC和ADO.NET)中的標準API都很熟悉,這些標準SQL API一般都很是強壯,爲開發人員 提供了巨大的靈活性。如下就是Java語言中動態SQL的一個簡單示例:編程語言
String name; Date hiredate; String sql = "SELECT emp_name, hire_date" + " FROM employee WHERE emp_num = ?"; Connection conn = dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement (sql)';
ps.setlnt (1, 28959);
ResultSet rs = ps.executeQuery();
while (rs.next) {
name = rs.getstring("emp_name");
hiredate = rs.getDate("hire_date"); }
rs .close () ; 應該包裹在一個try-catch, conn.close() ;代碼塊中分佈式
毫無疑問,動態SQL沒有內聯SQL那麼優雅,甚至還比不上存儲過程(以上代碼中已經省略 了異常處理但仍是很是複雜)。這些API一般都很是複雜且冗長,就像咱們從以前的示例中所看到 的同樣。使用這樣的框架一般會帶來大量的代碼,而這些代碼每每又具備重複性。此外,SQL語 句自己也經常由於太長而沒法在一行代碼中寫完。這時就不得不將該SQL字符串打散爲多個子串 而後經過拼接(concatenat)操做組合起來。代碼中的字符串拼接操做使得SQL的可讀性大大下降, 給維護和使用都帶來了更多的困難。
那麼,既然將SQL放在數據庫中做爲存儲過程,或者放在語言中做爲內聯SQL,或者放在應 用程序中做爲-種數據結構都不是最合適的,那麼到底應該如何「處置」它呢?咱們迴避這個問 題。在現代面向對象的應用程序中,與關係數據庫交互的一個最引人注目的解決方案就是對象/ 關係映射工具的使用。
0/RM
0/RM (對象/關係映射)就是被設計爲用來簡化對象持久化工做的,它經過將SQL徹底從開 發人員的職責中排除來達到這個目的。在0/RM中,SQL是生成的。--些工具在應用程序構建或 編譯時靜態生成SQL,其餘一些則在運行時動態生成。SQL是基於應用程序中的類與關係數據庫 表之間的映射關係而生成的。除了不用寫SQL語句,使用0/RM工具的API一般也比典型的SQL API要簡單得多。0/RM其實並非一個新概念,它的歷史幾乎與面向對象編程語言的歷史同樣悠 久。只是近年來的許多進展才使得0/RM又成爲一個引人注目的持久化方法。
現代0/RM工具所作的決不只僅是簡單地產生幾條SQL語句。它們提供了一套完整的持久化 架構,可使你的整個應用程序從中受益。任何一個優秀的0/RM工具都提供了事務管理功能, 包括可用於處理本地事務以及分佈式事務的很是簡單的O/RM工具一般也會爲處理各類不一樣 類型的數據提供許多高速緩存策略以免沒必要要的數據庫訪問。0/RM工具能夠減小數據庫訪問 的另外一種方式就是數據延遲加載技術。延遲加載使得對數據的獲取操做被推遲到絕對必要時,即直到它們確實須要被使用的那一刻。
雖然具備那麼多優秀的特性,但0/RM工具仍然不是一顆「銀彈」,它並不是適用於全部的場景。 0/RM工具是基於一些假設和規則的。其中最廣泛的一個假設就是數據庫被恰當地規範化了。正如咱們討論的,那些最大的最有價值的數據庫每每並無被很好地規範化。這就會給映射帶來許多麻煩,甚至須要繞些彎路,或者在設計時對效率作些折衷。沒有哪個對象/關 系解決方案能夠支持每一種數據庫的每個特性、每一種能力以及設計上固有的缺陷。正如咱們 以前說過的,SQL不是一個可靠的標準。基於這些緣由,每個0/RM工具都只是任何一個特定數據庫所具備的所有功能的一個子集。
系列文章: