之前寫了一個程序,負責從一個集群中同步Hive數據到另一個集群中,代碼中有這么一步,指定好表格后,會首先判斷表格是否存在,不存在則創建,已經存在則提示是否覆蓋。
在我最初編寫程序的時候,兩個集群中的表格基本上都是一致的,所以當初沒有出什么問題。但是最近組長說這個程序干脆整合到平台里好了,所以找了一個前輩來幫我測試。
前輩不愧是前輩,噼里啪啦沒多久就找出一堆小問題(主要因為最初是給自己寫的,沒有考慮那么多),其中一個問題就是就是在他刪除了某張表之后,再次同步這張表的數據時,程序提示表已經存在,但是最終修復表格信息時確保了錯,提示表格不存在。
我很容易就想到應該是表格判斷那里出了問題。判斷表格是否存在我使用的是DatabaseMetadata類下的getTables(),這個方法有四個參數,可以根據指定的參數從元數據中獲取表格信息,理論上是不會出錯的,畢竟是元數據,而且刪除表格使用的Hue,刪除沒出任何問題,理論上元數據中的數據也應該刪掉的:
我針對那張表進行測試,發現返回的真的是true。
事實上,我對這個方法並不怎么熟悉,連這個判斷的方法也是從網上查到的。
所以,為了解決這個問題,我開始研究這個方法。首先看這個方法的描述:
Retrieves a description of the tables available in the given catalog.Only table descriptions matching the catalog, schema,
tablename and type criteria are returned.They are ordered by TABLE_TYPE, TABLE_CAT, TABLE_SCHEM and TABLE_NAME.
檢索給定目錄中可用表的說明。只返回與目錄、架構、表名和類型條件匹配的表說明。它們按表類型、表類別、表計划和表名稱排序。
它有四個參數:String catalog,String schemaPattern,String tableNamePattern,String[] types,分別表示:
catalog 包含目錄名稱的 String。對此參數提供 Null 值表示無需使用目錄名稱。
schema 包含架構名稱模式的 String 值。對此參數提供 Null 值表示無需使用架構名稱。
tableNamePattern 包含表名稱模式的 String。
types 含有要包含的表類型的字符串數組。Null 表示應包含所有表類型。
最初我提供的參數是null, null, table ,null,即僅提供表名,因為當初查到的就是這樣的,而且catalog和schema代表什么我也不清楚。
這種做法下在最初是沒有什么問題的,但是到底為什么會導致查詢出一張已經被刪除的表?
我注意到了參數中的"tableNamePattern",而不是"tableName"或"table",所以是不是因為這個原因,它匹配到了其他表?
因為在Hive中我當初為了測試建立過幾張副表(假設原表名為A,另外幾張表是A2,A3等)。
所以我開始嘗試替換掉"_",並且指定頭尾(^ $ )進行精准匹配,然而反而任何表都匹配不到了。經過了數十分鍾的測試,我最終認為原因應該不在這里。
getTables()方法的結果集中可能有以下列:
TABLE_CAT String=>表目錄(可能為空)
TABLE_SCHEM String=>表架構(可能為空)
TABLE_NAME String=>表名
TABLE_TYPE String =>表類, 典型的類型有"TABLE","VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY","LOCAL TEMPORARY", "ALIAS", "SYNONYM"
REMARKS String => 表格注釋
TYPE_CAT String => 目錄類型(可能為空)
TYPE_SCHEM String => 架構類型(可能為空)
TYPE_NAME String => 類型名(可能為空)
SELF_REFERENCING_COL_NAME String => 類型表的指定“標識符”列的名稱(可能為空)
REF_GENERATION String => 指定如何創建引用_col_name的inself_值。值為"SYSTEM", "USER", "DERIVED"(可能為空)
我在想,方法中匹配到的真的是那張表的信息嗎?於是我編寫了以下方法,輸出所查詢到的表的信息:
輸出如下(A為我所查詢的表名):
查詢到的的確是這張表,但是這張表所在的庫卻是"test",我趕緊去test庫中看了一下,發現里面真的存在一張A表,我這才想起來,這不是我當初寫程序的時候創建的測試表嗎?!!
鬧了半天是被以前的自己坑了,但是這個問題也是很有價值的。
在輸出中可以看到,第一列代表參數catalog,第二列代表參數schemaPattern,第三列代表參數tableNamePattern,第四列代表參數types。
所以參數schemaPattern應該指定為數據庫,這樣就能利用到我最初傳入的參數database了。
將方法修改為:
接着進行測試,發現果然返回了false!最終,在困擾了我兩個多小時后,這個問題終於得以解決。
以上就是我在使用DatabaseMetadata.getTables()方法時遇到的一個小問題,希望能夠給予大家幫助。