本節含有可協助您在 XDS 事件中內嵌 SQL 的資訊。
所有範例都會參考下列 indirect.usr 表格。
CREATE TABLE indirect.usr ( idu INTEGER NOT NULL, fname VARCHAR2(64), lname VARCHAR2(64),
CONSTRAINT pk_usr_idu PRIMARY KEY(idu) );
內嵌式 SQL 可讓您在 XDS 格式的 XML 文件中內嵌 SQL 陳述式。 您可以與 XDS 事件結合使用或獨立使用內嵌式 SQL 陳述式。 內嵌式 SQL 陳述式獨立使用時,內嵌式 SQL 處理不需要驅動程式瞭解目標資料庫中的表格/檢視窗。 因此,驅動程式可以在不瞭解綱要的模式中執行。 請參閱同步化過濾器。 獨立使用內嵌式 SQL 時,您必須手動建立關聯。 驅動程式不會為您建立它們。
與 XDS 事件結合使用時,內嵌式 SQL 可以做為虛擬的資料庫觸發。 您可以在表格上安裝資料庫觸發,且會在執行某些 SQL 陳述式時在資料庫中產生副作用,與此相同,內嵌式 SQL 也會為回應某些 XDS 事件而在資料庫中產生副作用。
您可以藉由在 XDS 事件中內嵌 SQL,以完成下列操作:
您可以設定、檢查或修改使用者密碼。
範例組態檔案 JDBCv2.xml 會示範如何做為 XDS 事件的副作用,建立資料庫使用者、管理使用者密碼和管理使用者權限。若要啟用資料庫使用者帳戶管理,請將全域組態變數 (Global Configuration Variable, GCV) user-ddl 設為 true。 內嵌式 SQL 範例包含在「訂閱者」通道上的 User DDL「指令轉換」樣式表中。
SQL 會透過 <jdbc:statement> 和 <jdbc:sql> 元素內嵌在 XDS 事件中。 <jdbc:statement> 元素可以包含一或多個 <jdbc:sql> 元素。
當在 XML 文件的外部受到參考時,本節中使用的名稱空間字首 jdbc 會隱含地與名稱空間 urn:dirxml:jdbc 結合。
您必須使用名稱空間字首的內嵌式 SQL 元素和屬性。 否則,驅動程式將無法辨識它們。 在本節的所有範例中,使用的字首是 jdbc。實際上,只要字首與名稱空間值 urn:dirxml:jdbc 結合,它可以是您想要的任何字元。
下列 XML 範例說明如何使用並適當地建立內嵌式 SQL 元素的名稱空間字首。 在下列範例中,名稱空間宣告和名稱空間字首以粗體顯示:
<input xmlns:jdbc="urn:dirxml:jdbc"> <add class-name="usr"> <add-attr name="lname"> <value>Doe</value> </add-attr> </add> <jdbc:statement> <jdbc:sql>UPDATE indirect.usr SET fname = 'John'</jdbc:sql> </jdbc:statement> </input>
下列 XML 範例說明如何使用 <jdbc:statement> 和 <jdbc:sql> 元素以及它們的解譯。 在下列範例中,內嵌式 SQL 元素以粗體顯示:
<input xmlns:jdbc="urn:dirxml:jdbc"> <add class-name="usr"> <add-attr name="lname"> <value>Doe</value> </add-attr> </add> <jdbc:statement> <jdbc:sql>UPDATE indirect.usr SET fname = 'John'</jdbc:sql> </jdbc:statement> </input>
因為「訂閱者」通道會將 <add> 事件解析為一或多個 INSERT 陳述式,所以上面顯示的 XML 會解析為:
SET AUTOCOMMIT OFF INSERT INTO indirect.usr(lname)VALUES('Doe'); COMMIT; --explicit commit UPDATE indirect.usr SET fname = 'John'; COMMIT; --explicit commit
「訂閱者」通道支援內嵌式 SQL 陳述式的記號替換,而不需要您從關聯剖析欄位值。 在下列範例中,記號及其參考的值都以粗體顯示:
<input xmlns:jdbc="urn:dirxml:jdbc"> <modify class-name="usr"> <association>idu=1,table=usr,schema=indirect</association> <modify-attr name="lname"> <add-value> <value>DoeRaeMe</value> </add-value> </modify-attr> </modify> <jdbc:statement> <jdbc:sql>UPDATE indirect.usr SET fname = ’John’ WHERE idu = {$idu}</jdbc:sql> </jdbc:statement> </input>
記號預留位置必須遵循 XSLT 屬性值範本語法 {$field-name}。同時,參考的關聯元素必須在 XDS 文件中的 <jdbc:statement> 元素前,或者必須呈現為 <jdbc:statement> 元素的子代。 或者,如果不複製關聯元素做為 <jdbc:statement> 元素的子代,也可以將包含關聯元素的元素 src-entry-id 複製到 <jdbc:statement> 元素上。 在下列範例中,這兩種方法都以粗體顯示:
<input xmlns:jdbc="urn:dirxml:jdbc"> <modify class-name="usr"> <association>idu=1,table=usr,schema=indirect</association> <modify-attr name="lname"> <add-value> <value>DoeRaeMe</value> </add-value> </modify-attr> </modify> <jdbc:statement> <association>idu=1,table=usr,schema=indirect</association> <jdbc:sql>UPDATE indirect.usr SET fname = ’John’ WHERE idu = {$idu}</jdbc:sql> </jdbc:statement> </input>
<input xmlns:jdbc="urn:dirxml:jdbc"> <modify class-name="usr" src-entry-id="0"> <association>idu=1,table=usr,schema=indirect</association> <modify-attr name="lname"> <add-value> <value>DoeRaeMe</value> </add-value> </modify-attr> </modify> <jdbc:statement src-entry-id="0"> <jdbc:sql>UPDATE indirect.usr SET fname = ’John’ WHERE idu = {$idu}</jdbc:sql> </jdbc:statement> </input>
{$欄位名稱}記號必須參考關聯值中之其中一個命名相對可辨識名稱 (Relative Distinguished Name,RDN) 屬性名稱。 以上範例只有一個命名屬性: idu。
由於關聯尚未建立,所以 <add> 事件是關聯元素不需要在內嵌式 SQL 陳述式前加上記號的唯一事件。 此外,任何使用記號的內嵌式 SQL 陳述式,都必須加在 <add> 事件之後,而不是在它之前。 例如:
<input xmlns:jdbc="urn:dirxml:jdbc"> <add class-name="usr"> <add-attr name="lname"> <value>Doe</value> </add-attr> </add> <jdbc:statement> <jdbc:sql>UPDATE indirect.usr SET fname = ’John’ WHERE idu = {$idu}</jdbc:sql> </jdbc:statement> </input>
若要阻止任何人追蹤機密資訊,您可以使用 {$$password} 記號,參考相同文件內直接加在 <password> 元素之前的內容。 在下列範例中,password 記號及其參考的值,都以粗體字顯示:
<input xmlns:jdbc="urn:dirxml:jdbc"> <add class-name="usr"> <password>some password</password> <add-attr name="fname"> <value>John</value> </add-attr> <add-attr name="lname"> <value>Doe</value> </add-attr> </add> <jdbc:statement> <jdbc:sql>CREATE USER jdoe IDENTIFIED BY {$$password}</jdbc:sql> </jdbc:statement> </input>
此外,您也可以參考由「應用程式密碼」參數指定為 {$$$driver-password} 的驅動程式資料庫驗證密碼。 請參閱應用程式密碼。 目前尚不支援具名密碼替代功能。
如同關聯元素的情況,在 XDS 文件中參考的密碼元素必須在 <jdbc:statement> 元素之前,或者必須呈現為 <jdbc:statement> 元素的子代。 或者,不將密碼元素複製為 <jdbc:statement> 元素的子代,而是將包含密碼元素之元素的 src-entry-id 複製到 <jdbc:statement> 元素中。 在下列範例中,這兩種方法都以粗體字顯示:
<input xmlns:jdbc="urn:dirxml:jdbc"> <add class-name="usr"> <password>some password</password> <add-attr name="fname"> <value>John</value> </add-attr> <add-attr name="lname"> <value>Doe</value> </add-attr> </add> <jdbc:statement> <password>some password</password> <jdbc:sql>CREATE USER jdoe IDENTIFIED BY {$$password}</jdbc:sql> </jdbc:statement> </input>
<input xmlns:jdbc="urn:dirxml:jdbc"> <add class-name="usr" src-entry-id="0"> <password>some password</password> <add-attr name="fname"> <value>John</value> </add-attr> <add-attr name="lname"> <value>Doe</value> </add-attr> </add> <jdbc:statement src-entry-id="0"> <jdbc:sql>CREATE USER jdoe IDENTIFIED BY {$$password}</jdbc:sql> </jdbc:statement> </input>
資料庫觸發可以在觸發陳述式之前或之後引發;相同的,內嵌式 SQL 也可以定位在觸發 XDS 事件之前或之後。 下列範例顯示如何將 SQL 內嵌在 XDS 事件之前或之後。
<input xmlns:jdbc"urn:dirxml:jdbc"> <jdbc:statement> <association>idu=1,table=usr,schema=indirect</association> <jdbc:sql>UPDATE indirect.usr SET fname = 'John' WHERE idu = {$idu}</jdbc:SQL> </jdbc:statement> <modify class-name="usr"> <association>idu=1,table=usr,schema=indirect</association> <modify-attr name="lname"> <remove-all-values/> <add-value> <value>Doe</value> </add-value> </modify-attr> </modify> </input>
此 XML 會解析為:
SET AUTOCOMMIT OFF UPDATE indirect.usr SET fname = 'John' WHERE idu = 1; COMMIT; --explicit commit UPDATE indirect.usr SET lname = 'Doe' WHERE idu = 1; COMMIT; --explicit commit
<input xmlns:jdbc"urn:dirxml:jdbc"> <modify class-name="usr"> <association>idu=1,table=usr,schema=indirect</association> <modify-attr name="lname"> <remove-all-values/> <add-value> <value>Doe</value> </add-value> </modify-attr> </modify> <jdbc:statement> <jdbc:sql>UPDATE indirect.usr SET fname = 'John' WHERE idu = {$idu}</jdbc:sql> </jdbc:statement> </input>
此 XML 會解析為:
SET AUTOCOMMIT OFF UPDATE indirect.usr SET lname = 'Doe' WHERE idu = 1; COMMIT; --explicit commit UPDATE indirect.usr SET fname = 'John' WHERE idu = 1; COMMIT; --explicit commit
您可以使用兩個自定屬性,以手動方式將內嵌式 SQL 和 XDS 事件組合在一起:
此屬性具有兩個值: manual 和 auto。在預設狀態下,大部份相關的 XDS 事件 (<add>、<modify> 和 <delete>) 都以隱含方式設為手動異動類型。 手動設定可讓 XDS 事件解析為由一或多個 SQL 陳述式組成的異動。
由於部份 SQL 陳述式 (例如,資料定義語言 (DDL) 陳述式) 通常無法包含在手動異動中,因此,在預設狀態下,內嵌式 SQL 事件會設為自動異動類型。 在下列範例中,屬性以粗體字顯示。
<input xmlns:jdbc="urn:dirxml:jdbc"> <add class-name="usr" jdbc:transaction-type="auto"> <add-attr name="lname"> <value>Doe</value> </add-attr> </add> <jdbc:statement> <jdbc:sql>UPDATE indirect.usr SET fname = ’John’ WHERE idu = {$idu}</jdbc:sql> </jdbc:statement> </input>
此 XML 會解析為:
SET AUTOCOMMIT ON INSERT INTO indirect.usr(lname) VALUES(’Doe’); -- implicit commit UPDATE indirect.usr SET fname = ’John’ WHERE idu = 1; -- implicit commit
除非元素的 jdbc:transaction-type 屬性值預設為或明確地設為 manual,否則「訂閱者」通道會忽略此屬性。下列 XML 顯示手動異動的範例。 屬性以粗體字顯示。
<input xmlns:jdbc="urn:dirxml:jdbc"> <add class-name="usr" jdbc:transaction-id="0"> <add-attr name="lname"> <value>Doe</value> </add-attr> </add> <jdbc:statement jdbc:transaction-type="manual" jdbc:transaction-id="0"> <jdbc:sql>UPDATE indirect.usr SET fname = ’John’ WHERE idu = {$idu}</jdbc:sql> </jdbc:statement> </input>
此 XML 會解析為:
SET AUTOCOMMIT OFF INSERT INTO indirect.usr(lname) VALUES('Doe’); UPDATE indirect.usr SET fname = ’John’ WHERE idu = 1; COMMIT; -- explicit commit
除了群組陳述式之外,您可以使用異動來保留資料庫中的資料完整性。 異動可以鎖定資料,以防止同時進行存取或修改。 異動的隔離層級決定鎖定的設定方式。 通常,驅動程式使用的預設隔離層級是足夠的,而且不應該更動。
自定屬性 jdbc:isolation-level 可讓您在必要時調整隔離異動層級。 java.sql.Connection 參數會在介面中定義五個可能的值。 請參閱 java.sql.Connection。
除非由描述元檔案置換,否則驅動程式的預設異動隔離層級是 read committed。 在手動異動中,將 jdbc:isolation-level 屬性置於異動的第一個元素。 後續元素會忽略此屬性。 在下列範例中,屬性以粗體字顯示。
<input xmlns:jdbc="urn:dirxml:jdbc"> <add class-name="usr" jdbc:transaction-id="0" jdbc:isolation-level="serializable"> <add-attr name="lname"> <value>Doe</value> </add-attr> </add> <jdbc:statement jdbc:transaction-type="manual" jdbc:transaction-id="0"> <jdbc:sql>UPDATE indirect.usr SET fname = ’John’ WHERE idu = {$idu}</jdbc:sql> </jdbc:statement> </input>
此 XML 會解析為:
SET AUTOCOMMIT OFF SET TRANSACTION ISOLATION LEVEL SERIALIZABLE INSERT INTO indirect.usr(lname) VALUES(’Doe’); UPDATE indirect.usr SET fname = ’John’ WHERE idu = 1; COMMIT; -- explicit commit
「訂閱者」通道雖執行內嵌式 SQL 陳述式,卻不瞭解它們。 JDBC 1 介面會定義數種執行不同類型之 SQL 陳述式的方法。 下表包含這些方法:
Table 5-24 執行 SQL 陳述式的方法
最簡單的解決方案是將所有的 SQL 陳述式映射到 java.sql.Statement.execute(String sql):boolean 方法。 在預設狀態下,「訂閱者」通道會使用此方法。
有些協力廠商驅動程式 (特別是 Oracle 的 JDBC 驅動程式) 會錯誤地實作用於決定此方法所產生之結果集數的方法。 於是,驅動程式因而陷入無限迴路中,導致 CPU 使用率過高。 若要避免這個問題,您可以使用任意 <jdbc:statement> 元素上的 jdbc:type 屬性,將其包含的 SQL 陳述式映射到下列方法,而非預設的方法:
jdbc:type 屬性具有兩個值: update 和 query。針對 INSERT、UPDATE 或 DELETE 陳述式,將值設為 update。針對 SELECT 陳述式,將值設為 query。在沒有此屬性的情況下,驅動程式會將所有的 SQL 陳述式映射到預設的方法。 如果置於 <jdbc:statement> 以外的任何元素,則會忽略此屬性。
建議:
下列 XML 顯示 jdbc:type 屬性的範例。 屬性以粗體字顯示。
<input xmlns:jdbc="urn:dirxml:jdbc"> <add class-name="usr"> <add-attr name="lname"> <value>Doe</value> </add-attr> </add> <jdbc:statement jdbc:type="update"> <jdbc:sql>UPDATE indirect.usr SET fname = ’John’ WHERE idu = {$idu}</jdbc:sql> </jdbc:statement> </input>
為了完全支援資料庫的查詢功能,並避免將原始 SQL 查詢轉譯為 XDS 格式所帶來的困難,驅動程式會支援原始 SQL 查詢處理。 您可以使用與其他任何 SQL 陳述式完全相同的方法,將 select 陳述式內嵌於 XDS 文件。
例如,假設表格 usr 具有下列內容:
以下 XML 文件會產生含有單一結果集的輸出文件。
<input xmlns:jdbc="urn:dirxml:jdbc"> <jdbc:statement jdbc:type="query"> <jdbc:sql>SELECT * FROM indirect.usr</jdbc:sql> </jdbc:statement> </input>
<output xmlns:jdbc="urn:dirxml:jdbc"> <jdbc:result-set jdbc:number-of-rows="1"> <jdbc:row jdbc:number="1"> <jdbc:column jdbc:name="idu" jdbc:position="1" jdbc:type="java.sql.Types.BIGINT <jdbc:value>l</jdbc:value> </jdbc:column> <jdbc:column jdbc:name="fname" jdbc:position="2" jdbc:type="java.sql.Types.VARCHAR> <jdbc:value>John</jdbc:value> </jdbc:column> <jdbc:column jdbc:name="lname" jdbc:position="3" jdbc:type="java.sql.Types.VARCHAR> <jdbc:value>Doe</jdbc:value> </jdbc:column> </jdbc:row> </jdbc:result-set> <status level="success"/> </output>
無論結果集是否包含列,SQL 查詢都會產生單一 <jdbc:result-set> 元素。 如果結果集為空,則 jdbc:number-of-rows 屬性會設為零。
您可以在文件中內嵌一個以上的查詢。 SQL 查詢不需要讓驅動程式看到同步化綱要中參考的表格/檢視窗。 不過,XDS 查詢需要。
一般來說,由於大部份資料庫都不允許混合的資料操作語言 (DML) 和資料定義語言 (DDL) 異動,所以不可能在資料庫觸發中執行 DDL 陳述式。 雖然虛擬觸發沒有克服此執行屬性限制,卻允許讓資料定義語言 (DDL) 陳述式當成 XDS 事件的副作用來執行。
例如:
<input xmlns:jdbc="urn:dirxml:jdbc"> <add class-name="usr"> <add-attr name="fname"> <value>John</value> </add-attr> <add-attr name="lname"> <value>Doe</value> </add-attr> </add> <jdbc:statement> <jdbc:sql>CREATE USER jdoe IDENTIFIED BY novell</jdbc:sql> </jdbc:statement> </input>
此 XML 會解析為:
SET AUTOCOMMIT OFF INSERT INTO indirect.usr(fname, lname) VALUES(’John’, ’Doe’); COMMIT; -- explicit commit SET AUTOCOMMIT ON CREATE USER jdoe IDENTIFIED BY novell; -- implicit commit
使用 jdbc:transaction-id 和 jdbc:transaction-type 屬性將資料操作語言 (DML) 和資料定義語言 (DDL) 陳述式組成為單一異動,會使異動在大多數資料庫上復原。 因為資料定義語言 (DDL) 陳述式通常都當成不同異動來執行,所以上面範例中的 insert 陳述式可能會成功,而且 create user 陳述式可能會復原。
不過,不可能是 insert 陳述式失敗,而 create user 陳述式成功。 驅動程式會在第一個異動復原的點上,停止執行鏈結異動。
因為在單一異動中通常不可能混合資料操作語言 (DML) 和資料定義語言 (DDL) 陳述式,所以單一事件可包含一或多個異動。 您可以使用 jdbc:op-id 和 jdbc:op-type,將多個異動組成為單一邏輯操作。 此時,操作的所有成員都會處理為和狀態相關的單一單位。 如果一個成員有錯誤,所有的成員都會傳回相同的狀態層級。 同樣地,所有的成員都共享相同的狀態類型。
<input xmlns:jdbc="urn:dirxml:jdbc"> <add class-name="usr" jdbc:op-id="0" jdbc:op-type="password-set-operation"> <add-attr name="fname"> <value>John</value> </add-attr> <add-attr name="lname"> <value>Doe</value> </add-attr> <password>Doe{$idu}</password> </add> <jdbc:statement jdbc:op-id="0"> <jdbc:sql>CREATE USER jdoe IDENTIFIED BY {$$password} </jdbc:sql> </jdbc:statement> </input>
除了邏輯操作中的第一個元素外,所有元素都會忽略 jdbc:op-type 屬性。
密碼的啟始設定,通常都會藉由建立資料庫使用者帳戶來完成。 假設在「訂閱者」通道上產生 <add> 事件的情況下,下列舉出了由 XSLT 樣式表所產生的輸出範例,而這些樣式表將密碼設定當成 XDS <add> 事件的副作用來實作:
<input xmlns:jdbc="urn:dirxml:jdbc"> <add class-name="usr" jdbc:op-id="0" jdbc:op-type="password-set-operation"> <add-attr name="fname"> <value>John</value> </add-attr> <add-attr name="lname"> <value>Doe</value> </add-attr> <password>Doe{$idu}</password> </add> <jdbc:statement jdbc:op-id="0"> <jdbc:sql>CREATE USER jdoe IDENTIFIED BY {$$password} </jdbc:sql> </jdbc:statement> </input>
在邏輯上,<add> 事件會由 jdbc:op-id 和 jdbc:op-type 屬性結合至 CREATE USER 資料定義語言 (DDL) 陳述式。
JDBCv2.xml 範例組態檔案中的 User DDL「指令轉換」樣式表包含範例 XSLT 範本,其會將使用者帳戶建立資料定義語言 (DDL) 陳述式結合至支援它們的所有資料庫的 <add> 事件。
密碼的啟始設定,通常都會藉由變更現有的資料庫使用者帳戶來完成。 假設在「訂閱者」通道上產生 <modify-password> 事件,則下列是由實作 modify-password 之 XSLT 樣式表所產生的輸出範例:
<input xmlns:jdbc="urn:dirxml:jdbc"> <modify-password jdbc:op-id="0" jdbc:op-type="password-set-operation"> <password>new password</password> </modify-password> <jdbc:statement jdbc:op-id="0"> <jdbc:sql>ALTER USER jdoe IDENTIFIED BY {$$password} </jdbc:sql> </jdbc:statement> </input>
在邏輯上,<modify-password> 事件會由 jdbc:op-id 和 jdbc:op-type 屬性結合至 ALTER USER 資料定義語言 (DDL) 陳述式。
JDBCv2.xml 範例組態中的 User DDL「指令轉換」樣式表包含範例 XSLT 範本,其會將密碼維護資料定義語言 (DDL) 陳述式結合至支援它們的所有資料庫的 <modify-password> 事件。
與密碼設定不同,檢查物件密碼不需要內嵌式 SQL 陳述式或屬性。 只需要使用者帳戶名稱。 這可以從關聯值 (假設以手動方式維護關聯)、目錄屬性或資料庫欄位取得。 如果是儲存在目錄或資料庫中,必須發出查詢才能取得值。
JDBCv2.xml 範例組態檔會將資料庫使用者帳戶名稱儲存在資料庫欄位中。
NOTE:有些資料庫 (例如,Sybase Adpative Server Enterprise 和 Microsoft SQL Server) 會區分使用者帳戶名稱與登入帳戶名稱。 因此,您可能需要儲存兩個名稱,而不是只儲存一個。
若要實作檢查物件密碼,可將 dest-dn 屬性值附加至 <check-object-password> 事件。 在以下範例中,dest-dn 屬性以粗體字顯示:
<input xmlns:jdbc="urn:dirxml:jdbc"> <check-object-password dest-dn="jdoe"> <password>whatever</password> </check-object-password> </input>
基於效能因素,呼叫包含多個 SQL 陳述式的單一預存程序/函數,比在 XDS 文件中內嵌多個陳述式好。
在下列範例中,優先使用單一預存程序或函數。
單一預存程序
<input xmlns:jdbc="urn:dirxml:jdbc"> <add class-name="usr"> <add-attr name="fname"> <value>John</value> </add-attr> <add-attr name="lname"> <value>Doe</value> </add-attr> </add> <jdbc:statement> <jdbc:sql>CALL PROCEDURE set_name('John', 'Doe')</jdbc:sql> </jdbc:statement> </input>
多個內嵌式陳述式
<input xmlns:jdbc="urn:dirxml:jdbc"> <add class-name="usr"> <add-attr name="lname"> <value>Doe</value> </add-attr> </add> <jdbc:statement> <jdbc:sql>UPDATE indirect.usr SET fname = 'John' WHERE idu = {$idu}</jdbc:sql> </jdbc:statement> <jdbc:statement> <jdbc:sql>UPDATE indirect.usr SET lname = 'Doe' WHERE idu = {$idu}</jdbc:sql> </jdbc:statement> </input>
用於呼叫預存程序或函數的語法,因資料庫而不同。 如需其他資訊,請參閱預存程序和函數 JDBC 呼叫語法。