步驟清單
要解決沖突問題,我們應首先理解何謂沖突。
在向統一數據庫中上載行時可能會發生沖突。如果兩個用戶修改不同遠程數據庫中相同的行,則當這兩行中的第二個到達 MobiLink 同步服務器時將出現沖突。在沖突發生時,您應定義一個過程以計算正確值,或至少使用日志文件記錄沖突。
在同步的下載階段,遠程數據庫中不會出現沖突。如果下載的行中包含一個新的主鍵,則該行的值將插入到新的一行。如果該主鍵與一個現有行的主鍵相匹配,則會更新該行中的值。
沖突與錯誤是兩個不同的概念。沖突處理是應用程序應該包含的一部分。
只有在更新行的過程中才會檢測到沖突。嘗試更新自上一次同步後已更新或刪除的行將會導致沖突。缺省情況下:
*如果在嘗試插入一行時發現此行已經插入,則會導致錯誤。
*如果在嘗試刪除一行時發現此行已經刪除,則此嘗試刪除的操作將被忽略。
這些是為方便操作而定義的內置行為。如果需要不同的行為,可以使用一個或多個上載事件自行實現。
我們在demo的前半部分展示了有沖突而未解決的情況。當兩個不同的客戶端分別將相同的數據進行不同更改後,再在不同時間上載,後上載的數據成了最終結果。這可能是我們不想要的情況。我們需要對沖突進行一定的檢測、然後再根據我們的用戶規則進行處理。
在 MobiLink 客戶端向 MobiLink 同步服務器發送一個更新後的行時,發送的數據中不僅包含該行的新值(後映像),而且還將包含舊行值的副本(前映像)。如果前映像與統一數據庫中的當前值不匹配,表示檢測到了沖突。
檢測沖突的方法有兩種:
*定義一個 upload_fetch 腳本。
*定義一個 upload_update 腳本,該腳本在 WHERE 子句中包含所有非主鍵列。
如果為同一個表定義這兩個腳本,則只使用 upload_fetch 腳本。
僅當使用 upload_fetch 腳本或適當的 upload_update 腳本時,MobiLink 同步服務器才檢測沖突。如果提供了 upload_fetch 腳本,MobiLink 同步服務器會將上載的前映像與 upload_fetch 腳本返回的包含相同主鍵值的行值進行比較。如果存在前映像中的值與當前統一數據庫中的值不匹配的情況,則表示 MobiLink 同步服務器檢測到了沖突。
我們這裡用upload_fetch:
CALL ml_add_table_script( 'remote1', 'upload_fetch', 'SELECT empno, empname, gender, deptno, last_modifIEd FROM emp WHERE empno = ?' )
出現沖突時,可以使用臨時表(或永久表)和 resolve_conflict 腳本加以解決。
例如,我們可以先建兩個臨時表,然後在upload_old_row_insert表事件中把統一數據庫的舊值插入專門存放舊值的臨時表,然後再 upload_new_row_insert表事件中把想要更新的值插入專門存放新值的臨時表。接下來就可以在resolve_conflict表事件中解決沖突了。
當然,除了通過resolve_conflict事件解決沖突,我們也可利用upload_update、end_upload來解決沖突。在本部分的屏幕錄像中,我們先展示了沒有自定義沖突處理時候MobiLink對沖突的默認解決方案,即後者決定的策略。在此之後,我們又自定義了新的MobiLink沖突解決方案,讓部門號較小的更新成為最終值。
本部分的腳本如下:
先建立兩個目錄:remote1 & remote2。
把數據庫分別拷貝。
啟動個數據庫,中心叫center,其余兩個一個叫remote1,一個叫remote2。
重新建立remote1和remote2的ODBC
對3個庫分別執行:
ALTER TABLE emp ADD last_modified TIMESTAMP DEFAULT TIMESTAMP dbisql: remote1: CREATE PUBLICATION Lab_05 ( TABLE emp ) CREATE SYNCHRONIZATION USER "remote1" CREATE SYNCHRONIZATION SUBSCRIPTION TO Lab_05 FOR "remote1" TYPE 'TCPIP' ADDRESS 'host=localhost;port=2439' OPTION ScriptVersion='remote1' remote2: CREATE PUBLICATION Lab_05 ( TABLE emp ) CREATE SYNCHRONIZATION USER "remote2" ALTER SYNCHRONIZATION SUBSCRIPTION TO Lab_05 FOR "remote2" TYPE 'TCPIP' ADDRESS 'host=localhost;port=2439' OPTION ScriptVersion='remote1' center: CALL ml_add_table_script('remote1', 'emp', 'download_cursor', 'SELECT * FROM emp WHERE last_modifIEd > ?'); CALL ml_add_table_script('remote1', 'emp', 'upload_update', 'UPDATE emp SET empname=?, gender=?, deptno=? WHERE empno=?'); COMMIT
命令行下:
dbmlsrv9 -c "dsn=center" -v+ -x tcpip -dl -o mlserver.mls -zu+ dbmlsync -c "dsn=remote1" -v -o dbmlsync1.out -e "sv=remote1" dbmlsync -c "dsn=remote2" -v -o dbmlsync2.out -e "sv=remote1"
對remote2:
UPDATE emp SET deptno = '0005' WHERE empno = 1 COMMIT
再次同步remote2
dbmlsync -c "dsn=remote2" -v -o dbmlsync2.out -e "sv=remote1"
對remote1
UPDATE emp SET deptno = '0002' WHERE empno = 1 COMMIT
同步remote1
dbmlsync -c "dsn=remote1" -v -o dbmlsync1.out -e "sv=remote1"
對center:
CREATE GLOBAL TEMPORARY TABLE emp_new( empno INTEGER NOT NULL PRIMARY KEY, empname VARCHAR(20), gender BIT, deptno CHAR(4), last_modified TIMESTAMP); CREATE GLOBAL TEMPORARY TABLE emp_old( empno INTEGER NOT NULL PRIMARY KEY, empname VARCHAR(20), gender BIT, deptno CHAR(4), last_modified TIMESTAMP) CALL ml_add_connection_script( 'remote1', 'end_upload', 'DROP TABLE emp_new; DROP TABLE emp_old'); CALL ml_add_table_script( 'remote1', 'upload_fetch', 'SELECT empno, empname, gender, deptno, last_modifIEd FROM emp WHERE empno = ?' ) CALL ml_add_table_script( 'remote1', 'emp', 'upload_old_row_insert', 'INSERT INTO emp_old VALUES(?,?,?,?)'); CALL ml_add_table_script( 'remote1', 'emp', 'upload_new_row_insert', 'INSERT INTO emp_new VALUES(?,?,?,?)'); CALL ml_add_table_script( 'remote1', 'emp', 'resolve_conflict', 'CALL ResolveConflictDemo()'); COMMIT; ALTER OR REPLACE PROCEDURE ResolveConflictDemo() BEGIN UPDATE emp e SET e.deptno = en.deptno FROM emp_new en WHERE e.empno = en.empno AND en.deptno < e.deptno; DELETE FROM emp_new; DELETE FROM emp_old; END;