IBM Message Broker筆記系列(九)
這篇是純粹的“coding心得”,撇開MB那些囉嗦的配置不談,專門講學習ESQL的痛苦經歷,有些內容可能前面的筆記有介紹過,這裡做一個全面的彙總。雖然有些程式設計的tips已經忘記了,以後如果想起來還會繼續補充。
概述
ESQL的語法和資料庫的儲存過程語句很像,雖然我從未寫過儲存過程,但是平心而論,ESQL的基本語法和概念還是很好理解的,畢竟,ESQL沒有類、物件、多型這些OOP的東西,也沒有指標、位移操作這些C的概念;沒有C的函式指標、指標的指標、記憶體分配這種讓新手頭暈的術語,也不像Java那樣各類框架滿天飛,開足馬力都學不過來。所以,ESQL還是很好入門的。但是,切記,只是“入門”而已。你看懂那些示例的ESQL很容易,無非是邏輯樹的增刪改;訊息流也是那麼一目瞭然,訊息從一個節點出來,進入另一個節點,不知不覺一個“業務流”就完成了,so simple,naïve!我一開始也是這麼覺得的,但真正動手的時候,才發覺ESQL程式碼中,危機四伏!下面一一列舉
基本型別
數字
ESQL的基本型別很少,無非是數字、字串、邏輯、時間,還有引用。數字型別包括int、float和decimal(就是double,高精度小數),一般很少會考慮三者的差別,把它們與java的等同起來,其實不然,如果隨便亂用,會冒出很多無聊而又浪費時間的bug
- 資料庫查詢
在使用oracle的時候,通常都會用Number型別作為主鍵id等數字型別欄位,可是你知道用select語句取Number到ESQL中是什麼嗎?是decimal。由於ESQL裡面,訊息樹中的欄位型別是隱式的、可變的(類似PHP),也就是你可以隨便賦任何值給某個訊息節點。按理說這種指令碼語言的特性可以方便程式設計,是好事。不過請先看完下面的描述。
- 資料庫插入
這個問題是最近才發現的,在64位的linux上,MB使用64位資料來源訪問oracle,在一條insert語句上屢屢失敗,而這條insert語句之前在32位windows平臺上卻很正常的執行。丟擲的異常提示:“oracle:String data, right truncated”,在網上搜了一下大部分人都說是資料太長,只有dw論壇上有人說可能是64bit資料來源的關係,但具體原因也不清楚。請了IBM的支援來搞了半天也沒任何結果,絕望之際我乾脆用排除法,每次修改一兩個欄位為很簡單的常數(那樣總不會出問題了),在排除到最後一個欄位時,才發現把一個decimal的資料插進去會有問題,如果換成float就ok了!這個問題前後浪費了我兩天,當時忍不住說了幾句髒話,一個簡單的問題搞得這麼噁心,錯誤提示也純粹誤導使用者。天知道以後換成其他平臺會不會又這樣呢?
- 函式呼叫
ESQL是弱型別的?是的,某種程度上是弱型別的,可是遇到函式呼叫的時候,它的型別強度簡直勝過java——你不能把一個int作為引數傳遞給宣告為double的引數,那樣會丟擲異常。問題是有時候你根本不知道某個訊息樹節點啥時變成了int或者是float或是double,就像上文說到的資料庫查詢結果。請開啟debug,慢慢找吧,總會有柳暗花明的一刻
字串型別
估計MB為了照顧比較“原始”的訊息格式,即非XML、而是CWF或者TDS格式的訊息,ESQL的字串型別不僅僅有字元型別“char”,還有位元組型別“BLOB”和位元型別“BIT”,的確是大大方便了位元流的處理。關於字串,發現的問題不多,下面列出幾點需要稍加註意之處。
- 字串連線“||”
使用“||”連線字串時,記得每個被連線的變數都不能為null,否則連線後的結果就變成null了,可以用“變數 is not null”來判斷
- BLOB型別
BLOB型別在ESQL中的表示方式為 X'ABCD',實際上是一種BCD碼,每個字元表示一個十六進位制,即半個位元組。注意這裡要是偶數個長度,否則在打包或者部署時會報錯
時間型別
和一般程式語言不同的是ESQL有時間型別的變數,這很大程度上是因為MB裡面支援很多XML的特性,而時間型別也是標準XML中包含的,例如xsd:dateTime等等。我沒學過高階的XML,自然對這些名目繁多的時間型別之間的差別不甚瞭解,所以簡單地列出幾點比較常用的特性:
- 訊息定義中的時間型別
訊息定義檔案裡頭也可以宣告某個節點型別為timestamp(訊息定義檔案本質上就是XML SCHEMA檔案,自然支援xsd:名稱空間),不過在實踐中發現從MQ讀入的一個XML字串,解析為timestamp型別時,經常有一些格式上的問題而導致解析失敗,後來乾脆把timestamp全部替換為string了,IBM的技術支援也是這麼“推薦”的,估計是他們也找不出原因所在
- 計算花費的時間
JAVA裡面很常用的就是通過計算系統時間之差,來得到一段程式碼的執行時間毫秒數,然後用時間類可以進行格式轉換,ESQL同樣可以做到,而且更加簡單。比如要計算一個訊息流的執行時間,那麼在訊息流開頭用 CURRENT_TIME得到起始時間,儲存在環境樹中的T1節點;然後在訊息流結尾,再次用 CURRENT_TIME得到結束時間T2,兩個時間值相減,再用下面這段程式碼將其轉換成毫秒數
SET OutputRoot.MRM.process_time = CAST( (T2-Environment.Variables.T1) SECOND AS FLOAT) *1000;
很遺憾的,ESQL最小隻支援“秒”的時間間隔(“時間間隔”INTERVAL也是一種時間型別),不過得到的float值通常是小數位很長的,包含了毫秒資訊,譬如0.2352436,因此乘以1000也完全夠用
全域性變數
問過IBM的人好幾次,自己也去查了不少資料,一直沒有發現ESQL中有足夠理想的全域性變數或者全域性常量。我們知道,ESQL的程式碼層次從高到低依次是:schema->module->function or procedure,越是區域性的變數,優先順序越高,這一點和普通程式語言一樣。所以,沒有變數的宣告可以超越schema這一級,包括所謂的外部變數external,因此,在不同schema的訊息流之間不能共享全域性變數的,這個限制有時候很麻煩,比如所有訊息流都要訪問同一個資料來源、或者Oracle的schema,或者是你自己定義的全域性常量,那你就只能在每個schema中設定了,還好schema不會很多,或者你在訊息流開始的時候,從檔案、資料庫等地方讀取配置引數也是一種選擇。
對於定義好的全域性變數,可以用{ }進行變數值的替換,從而實現動態功能,比如 OutputBody.{myvar}.value,花括號的值會在執行期間指定。但是這樣一來ESQL的編輯器就無法判斷這個節點是否存在,會給出“無法解析該引用”的警告,這不影響使用。
全域性函式
剛才說到的在schema作用域中定義的全域性變數,在其他schema不能引用。但是在schema中定義的全域性函式或者過程,則可以在其他schema中引用,只要在定義schema時使用PATH將其他schema匯入即可,或者在呼叫函式時指定完整路徑,如 CALL com.xxx.GLOBAL_FUNCTION。很多人一開始會對全域性函式寄予厚望,因為可以減少程式碼的重複,增加複用度,實則符合聖人們的教誨。只可惜呢,全域性函式中不能使用通常在節點中的Root、ExceptionList、Environment等邏輯樹,所以我在定義全域性函式時,第一個引數通常都是REFERENCE型別,用來把Environment等邏輯樹傳進去。
陣列、ROW和LIST
ESQL裡面有陣列型別,但你不能DECLARE一個陣列變數;有ROW型別,同時有個ROW函式專門用來產生一個ROW變數,還有個LIST函式用來產生陣列。
先談談陣列,陣列是什麼大家都知道了,在ESQL裡面,由於不能宣告一個陣列,所以我習慣把陣列儲存在Environment或者LocalEnvironment中。因為訊息樹的每個節點都可以往下增加子結點,所以每個訊息樹的中間節點其實都是陣列,我們說 set LocalEnvironment.Variables.temp = xxx ,實際上就是 set LocalEnvironment.Variables.temp[1] = xxx
至於ROW型別,《精通WMB》上說是個XML單行資料,執行這條ESQL語句:set LocalEnvironment.root = ROW('aa' AS a, 'bb' AS b),(注意root旁邊沒有方括號[ ])生成的XML片段如下:
bb
然而,ROW其實是對應與資料庫的一行資料,僅此而已。上面的root節點相當於一行,a和b則是該行資料的欄位,就這麼簡單。所以,執行select語句時,返回的就是一個ROW的陣列
LIST函式是產生陣列用的,例如:set LocalEnvironment.Var.root[ ] =LIST( 'aa', 'bb'),(root旁邊這次有方括號[])產生如下XML:
aa bb
詳細內容,請參考老陳的《精通WMB》後面的附錄P321(我也是最近才無意中翻到ROW和LIST)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14789789/viewspace-444228/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 刷前端面經筆記(九)前端筆記
- Labview 安裝 NI 軟體時出現 ni-systemlink-message-broker 錯誤View
- robot framework學習筆記之九-雜記Framework筆記
- ReactNative學習筆記九之TabNavigatorReact筆記
- HexMap學習筆記(九)——地形特徵筆記特徵
- RocketMQ系列:使用systemd管理nameserver和brokerMQServer
- Linux 筆記分享九:ACL 許可權Linux筆記
- ES6學習筆記(九)【class】筆記
- SpringMVC原始碼系列:九大元件小記SpringMVC原始碼元件
- jQuery 學習系列筆記jQuery筆記
- JavaWeb學習筆記——第九天JavaWeb筆記
- 飛機的 PHP 學習筆記九:安全PHP筆記
- 筆記九:Request Body 跟 Query DSL 簡介筆記
- hive學習筆記之九:基礎UDFHive筆記
- iOS學習筆記49 Swift(九)訪問控制iOS筆記Swift
- Vue學習筆記(九):元件化程式設計Vue筆記元件化程式設計
- ES 筆記九:Request Body 跟 Query DSL 簡介筆記
- ES[7.6.x]學習筆記(九)搜尋筆記
- iOS開發筆記(九):UIViewController的生命週期iOS筆記UIViewController
- Java學習筆記系列-反射Java筆記反射
- Spring Boot系列筆記--整合RedisSpring Boot筆記Redis
- Kafka筆記系列-概念相關Kafka筆記
- Cris 的 Scala 筆記整理(九):物件導向高階筆記物件
- celery筆記九之task執行結果檢視筆記
- 19c 探索高可用系列(二) - RAC+DataGuard Broker
- Node系列-爬蟲踩坑筆記爬蟲筆記
- laracast 視訊教程系列筆記更新AST筆記
- 架構學習筆記系列三架構筆記
- 架構學習筆記系列二架構筆記
- 架構學習筆記系列一架構筆記
- 【隱私計算筆談】MPC系列專題(九):OT協議(二)協議
- Python零基礎學習筆記(九)——隨機數Python筆記隨機
- Linux學習筆記(九)Vim文字編輯器的使用Linux筆記
- Django筆記九之model查詢filter、exclude、annotate、order_byDjango筆記Filter
- Storm 系列(九)—— Storm 整合 KafkaORMKafka
- Netty原始碼研究筆記(4)——EventLoop系列Netty原始碼筆記OOP
- RTSP系列筆記-幾種鑑權方式筆記
- ibm筆記本用ghost win10不能啟動最佳解決方法IBM筆記Win10
- 《Go 語言程式設計》讀書筆記 (九) 命令工具集Go程式設計筆記