Get方法是用來(lái)從HBase中取出相應(yīng)的數(shù)據(jù)??梢愿鶕?jù)它們一次取出的條數(shù)分成兩類:?jiǎn)螚lGet、多條Get。 可以使用如下的接口從HBase出取出特定的數(shù)據(jù)出來(lái): Result get(Get 與Put類類似,Get類提供了一個(gè)get方法,在調(diào)用該方法時(shí),您同樣需要提供一個(gè)Get實(shí)例,該實(shí)例必須指定一個(gè)rowkey,它有如下的兩種創(chuàng)造函數(shù): Get(byte[] row) Get(byte[] row, 一個(gè)get方法從來(lái)取一個(gè)特殊的行,但可以取出這一行中的多個(gè)列。Get類的構(gòu)造函數(shù)必須指定一個(gè)row,第二個(gè)構(gòu)造函數(shù)還可以指定一個(gè)RowLock,允許您使用一個(gè)自己定義的行鎖。與Put類相似,Get類也指供了大量的方法從來(lái)設(shè)置您所要找的行,或者精確到一個(gè)具體的Cell: Get Get Get Get Get Get addFamily將查詢的行限制到特定的Column Family上。它可以被調(diào)用多次來(lái)添加多個(gè)Column Family。對(duì)于addColumn方法也是一樣的。您可以給Get實(shí)例添加更多的限制條件,比如時(shí)間戳范圍、版本數(shù)目等。 一次get操作允許取回一行記錄的多個(gè)版本,在不設(shè)置取回的版本數(shù)目下,默認(rèn)返回最近的一個(gè)版本。如果您有所懷疑,可以通過(guò)接口getMaxVersions()查看。對(duì)于無(wú)參的setMaxVersions()調(diào)用,會(huì)將版本數(shù)設(shè)為Integer.MAX_VALUE,從而取回這一行對(duì)應(yīng)的所有版本。Get類也提供了其它的一些函數(shù)調(diào)用,在表3-4中列出了他們的用法。 表3-4 Get類部分方法列舉
表3-4中表出的getter方法,只能取出對(duì)Get設(shè)置過(guò)的值。因此,他們很少被用到。 在前面提到過(guò),HBase提供了一個(gè)名為Bytes的幫助類,該類提供了很多的靜態(tài)方法實(shí)現(xiàn)Java中的類型與byte數(shù)組的轉(zhuǎn)換。它也提供了反向的轉(zhuǎn)換,即從byte數(shù)組,解析出相應(yīng)的Java類型。下面給出了Bytes類的一些方法: static String static boolean static long static float static int 示例3-8演示了如何使用它們: 示例3-8 從HBase中獲取數(shù)據(jù) Configuration conf HTable table = new Get get = new get.addColumn(Bytes.toBytes(“colfam1″), Result result = byte[] val = result.getValue(Bytes.toBytes(“colfam1″), Bytes.toBytes(“qual1″)); System.out.println(“Value: 首先創(chuàng)建一個(gè)HBase的配置文件,初始化一個(gè)HTable的實(shí)例。創(chuàng)建一個(gè)指定向row1的Get實(shí)例,向Get中添加一個(gè)colfam1的列,和一個(gè)qual1的qualifier。然后從HBase中取出這一行的對(duì)應(yīng)的數(shù)據(jù),最后將數(shù)據(jù)轉(zhuǎn)化成相應(yīng)的格式并打印出來(lái)。如果您運(yùn)行上述的示例代碼,應(yīng)該打印出: Value: val1 如果調(diào)用get()函數(shù)取出數(shù)據(jù),您將會(huì)得到一個(gè)Result對(duì)象,它持有所有相符的Cell。當(dāng)您使用特定的行、特定的查詢條件(如column family, 就像前面示例3-8給出的一樣,您可以得到更多的維度信息。比如,要求服務(wù)器返回指定column family的所有列,這樣您在客戶端側(cè)就可以通過(guò)get方法取得所有的列信息。下面給出了Result類提供的一些方法: byte[] byte[] value() byte[] getRow() int size() boolean isEmpty() KeyValue[] raw() List<KeyValue> getValue方法從HBase中一個(gè)特定的Cell中取出數(shù)據(jù)。您可以不設(shè)定時(shí)間戳、版本數(shù),從而獲得最近的一個(gè)版本數(shù)據(jù)。由于服務(wù)器上同一行的數(shù)據(jù)按照版本由新到舊的順序排度,因此,總是服務(wù)器查到的第一次記錄就是最新的一個(gè)版本。 前面已經(jīng)介紹過(guò)getRow():它返回rowkey,即在創(chuàng)建Get實(shí)例時(shí)指定的rowkey。size()方法可以得到服務(wù)器返回的KeyValue實(shí)例的數(shù)目。isEmpty可以判斷KeyValue實(shí)例的數(shù)目是否為空。 通過(guò)row方法,可以得到當(dāng)前Result實(shí)例后存儲(chǔ)的一組KeyValue實(shí)例數(shù)組,list方法可以將KeyValue數(shù)組對(duì)象轉(zhuǎn)化成一個(gè)List對(duì)象,從而可以簡(jiǎn)單地通過(guò)迭代器進(jìn)行訪問(wèn)。 raw()方法返回的數(shù)組已經(jīng)經(jīng)過(guò)了排序,排序的維度是Column family 還有一組面向Column的方法: List<KeyValue> KeyValue boolean containsColumn(byte[] 要得到一個(gè)列對(duì)應(yīng)的一組KeyValue,您必須先調(diào)用setMaxVersions設(shè)定要取得多個(gè)版本,否則只能得到一個(gè)KeyValue。getCOlumnLatest返回這個(gè)列對(duì)應(yīng)的最新的一個(gè)Cell。getValue()方法并不返回一個(gè)raw字節(jié)數(shù)組,而是返回KeyValue對(duì)象。containsColumn可以非常便捷的查看返回的Cell中是否指定的Column列。 所有的方法中的qualifier字段都可以設(shè)置為null,這樣可以匹配qualifier為空的列。Qualifier為空意味著列沒(méi)有label。當(dāng)查看一個(gè)表中的數(shù)據(jù)時(shí),比如使用shell命令,您必須了解表中有哪些列。很少會(huì)使用到空的qualifier,在這些情況下,意味著只有一個(gè)column,這時(shí)column family便起到了column的作用。 還有另一個(gè)方法集,可以對(duì)請(qǐng)求得到的數(shù)據(jù)進(jìn)行訪問(wèn)。它們是面向map的訪問(wèn)方式: NavigableMap<byte[], NavigableMap<byte[], NavigableMap<byte[], getMap是更通用的調(diào)用方式,以Java Map的方法,返回整個(gè)result集合,可以通過(guò)迭代的方式遍歷所有的值。getNoVersionMap()方法只返回最新的一個(gè)版本的數(shù)據(jù)。第三個(gè)getMap方法返回指定family下的所有版本的value值。 使用哪組接口訪問(wèn)Result對(duì)象取決于你的習(xí)慣; 數(shù)據(jù)已經(jīng)通過(guò)網(wǎng)絡(luò)從服務(wù)器轉(zhuǎn)輸?shù)搅丝蛻舳?,并不存在效率的差別。 put方法中,可以一次插入一組Put對(duì)象。類似地,get操作也允許一次從服務(wù)器上取一組Get對(duì)象。批量Get是一種高效地訪問(wèn)HBase的方法,但同樣不能保證多條數(shù)據(jù)之間的順序。 從前面的圖3-1可以看出來(lái),請(qǐng)求不只會(huì)發(fā)送到一臺(tái)服務(wù)器上,但從客戶端看來(lái),仿佛只有一條請(qǐng)求發(fā)出。 批量Get的API定義如下: Result[] 跟前面的批量put一樣,您需要先創(chuàng)建一個(gè)隊(duì)列來(lái)存儲(chǔ)Get實(shí)例,這些實(shí)例保存要請(qǐng)求的條件,而服務(wù)器端返回查詢出來(lái)的Result結(jié)果。示例3-9給出了如何使用兩種不同的方式取數(shù)據(jù)。 示例3-9 批量從HBase中取數(shù)據(jù) byte[] cf1 = byte[] qf1 = byte[] qf2 = byte[] row1 = byte[] row2 = List<Get> Get get1 = new get1.addColumn(cf1, gets.add(get1); Get get2 = new get2.addColumn(cf1, gets.add(get2); Get get3 = new get3.addColumn(cf1, gets.add(get3); Result[] results = System.out.println(“First for (Result result String System.out.print(“Row: byte[] if val System.out.println(“Value: } if val System.out.println(“Value: } } System.out.println(“Second for (Result result for System.out.println(“Row: ” Value: } } 示例中首先定義了一組byte數(shù)據(jù),用來(lái)存放column family的名字、column qualifier的名字、row的名字。然后創(chuàng)建一個(gè)List保存所有的Get請(qǐng)求對(duì)象。最后調(diào)用HTable的get方法,從服務(wù)器上批量讀取數(shù)據(jù)。在第一個(gè)迭代遍歷的過(guò)程中,只打印出colfam1、qual1對(duì)應(yīng)的列和colfam1、qual2對(duì)應(yīng)的值。第二個(gè)迭代遍歷的過(guò)程中打印出所有取到的值。 假設(shè)您在運(yùn)行了示例3-4之后,運(yùn)行示例3-9,那么您將得到如下的輸出: First iteration… Row: row1 Value: Row: row2 Value: Row: row2 Value: Second Row: row1 Value: Row: row2 Value: Row: row2 Value: 兩次迭代過(guò)程會(huì)打印相同的值。示例告訴您,如何訪問(wèn)批量get的結(jié)果。您現(xiàn)在還不了解的便是出錯(cuò)如何通知到您。這和前面講到的put是有所不同的,get操作要么取出與Get實(shí)例大小相等的結(jié)果,要么拋出一個(gè)異常。示例3-10給出一個(gè)例子: 示例3-10 讀出一個(gè)錯(cuò)誤的column family List<Get> Get get1 = new get1.addColumn(cf1, gets.add(get1); Get get2 = new get2.addColumn(cf1, gets.add(get2); Get get3 = new get3.addColumn(cf1, gets.add(get3); Get get4 = new Get(row2); get4.addColumn(Bytes.toBytes(“BOGUS”), gets.add(get4); Result[] results = System.out.println(“Result count: ” + results.length); 上述代碼首先將Get實(shí)例插入到一個(gè)List中,其中一個(gè)Get實(shí)例指定了一個(gè)虛假的column family值。因此,一個(gè)異常將會(huì)被拋出,最后的打印記錄永遠(yuǎn)不會(huì)輸出來(lái)。執(zhí)行上述代碼,將會(huì)得到一個(gè)如下的異常: org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException: Failed 1 action: servers with batch()是一種更有控制力的API,它能處理部分出錯(cuò)的情況。在后文的批量操作部分將會(huì)介紹到這個(gè)API。 相關(guān)解析數(shù)據(jù)方法 很多的函數(shù)都可以取出服務(wù)器返回的結(jié)果數(shù)據(jù),先介紹下面這個(gè): boolean exists(Get 該函數(shù)需先創(chuàng)建一個(gè)Get對(duì)象,它并不從服務(wù)器上取Get對(duì)象對(duì)應(yīng)的結(jié)果數(shù)據(jù),而是要求服務(wù)器返回是否存在對(duì)應(yīng)記錄的標(biāo)志。 Resion Server使用相同的處理流程來(lái)處理exists請(qǐng)求,包括加載文件塊來(lái)確定是否含對(duì)指定的column或rowkey。但數(shù)據(jù)并不經(jīng)過(guò)網(wǎng)絡(luò)傳輸。因此,對(duì)于一些大的column列,該方法還是很有用的。 有時(shí),您或許想請(qǐng)一個(gè)確定的row,或者在它前面的row,并取出相應(yīng)的數(shù)據(jù)。此時(shí),您可以調(diào)用下面的接口: Result 您必須指定相應(yīng)的row和一個(gè)column family,當(dāng)然column family不是必需的。結(jié)果返回您要找的row,或者是位于它前面的一個(gè)。如果一個(gè)也沒(méi)有找到,該方法返回null。示例3-11給出如何查詢前面put示例中插入的數(shù)據(jù)。 示例3-11 使用一個(gè)專門的讀取方法 Result result1 = Bytes.toBytes(“colfam1″)); System.out.println(“Found: Result result2 = Bytes.toBytes(“colfam1″)); System.out.println(“Found: for (KeyValue kv : System.out.println(” “/” “, } Result result3 = Bytes.toBytes(“colfam1″)); System.out.println(“Found: 示例中首先去尋找一個(gè)存在的row,并打印出找到的記錄。然后試圖去尋找一個(gè)不存在的row,打印出了表的最后一行記錄。最后,去尋找一個(gè)排在row1前的“abc”,將會(huì)打印出來(lái)null。 上述代碼的輸出如下: Found: row1 Found: row2 Col: Col: Found: null 第一次調(diào)用直接請(qǐng)求一個(gè)已經(jīng)存在的記錄會(huì)返回這條記錄。第二次調(diào)用請(qǐng)求了一個(gè)很大的row值“row99”,它顯然排在row2的后面,因此調(diào)用getRowOrBefore會(huì)得到row2的值。最后請(qǐng)求“abc”,按字母序,abc排在row1的前面。因此,調(diào)用getRowOrBefore會(huì)得到null。在循環(huán)打印第二次請(qǐng)求“row99”的結(jié)果時(shí),可以發(fā)現(xiàn)row2對(duì)應(yīng)的所有列均被取出,并按照qualifier的順序進(jìn)行排列。 您現(xiàn)在已經(jīng)可以創(chuàng)建、讀取和更新HBase表中的記錄了,下面將介紹刪除操作。您大概也可以猜出來(lái),HTable對(duì)象一定提供了一個(gè)類叫做Delete。 單條刪除 delete()方法有一種單條刪除接口形式,如下: void delete(Delete 與get、put調(diào)用相似,該調(diào)用首先要?jiǎng)?chuàng)建一個(gè)Delete實(shí)例,并將要?jiǎng)h除的詳細(xì)信息添加到這個(gè)實(shí)例中。Detele的創(chuàng)建函數(shù)如下: Delete(byte[] row) Delete(byte[] row, 您必須提供要?jiǎng)h除row的rowkey,或者額外提供一個(gè)RowLock。這和前面的put、get單條操作都是完全相同的。有時(shí),您或許不想將rowkey對(duì)應(yīng)的整行刪除,您只想刪除某個(gè)版本的記錄,或者是某個(gè)column family、某個(gè)column Delete Delete Delete Delete Delete void 第一個(gè)函數(shù)可以刪除指定的column family下的記錄,當(dāng)然也包括了它對(duì)應(yīng)的所有的column。第二個(gè)函數(shù)刪除指定的column family對(duì)應(yīng)的timestamp以前的所有版本的數(shù)據(jù)。第三個(gè)函數(shù)刪除指定的column family和指定的column 表3-5 delete()調(diào)用
表3-6列出了Delete類提供的另外一些方法。 表3-6
示例3-12給出了如何客戶端如何調(diào)用一個(gè)單條刪除方法。 示例3-12 HBase數(shù)據(jù)刪除 Delete delete = delete.setTimestamp(1); delete.deleteColumn(Bytes.toBytes(“colfam1″), delete.deleteColumns(Bytes.toBytes(“colfam2″), delete.deleteColumns(Bytes.toBytes(“colfam2″), delete.deleteFamily(Bytes.toBytes(“colfam3″)); delete.deleteFamily(Bytes.toBytes(“colfam3″), table.delete(delete); table.close(); 首先創(chuàng)建一個(gè)指向row1的Delete對(duì)象,為該Delete對(duì)象設(shè)定timestamp值為1。然后調(diào)用delete刪除Column的接口,并指定一個(gè)版本。然后刪除另一列colfam2:qual1下的所有版本,然后刪除該列colfam2:qual2下指定版本以前的所有版本。接著刪除colfam3下整個(gè)family,包含所有版本。再刪除colfam3下版本3以前的所有版本。最后執(zhí)行刪除操作。 在上面的示例給出了您可以使用的delete操作的所有函數(shù)形式。您可以依次執(zhí)行并觀察它們的輸出。 為Delete對(duì)象設(shè)定timestamp,使用deleteColumn接口只能刪除特定的cell,使用deleteColumns接口可以刪除精確的timestamp匹配得到比這個(gè)時(shí)間戳舊的所有版本(包括相等的)。 批量刪除 批量刪除操作同批量插入很相似,您需要?jiǎng)?chuàng)建一個(gè)Delete實(shí)例的列表,然后通過(guò)delete方法刪除它們。 void 示例3-13給出了一個(gè)批量刪除的例子。當(dāng)您運(yùn)行這個(gè)例子時(shí),將會(huì)打印刪除前后delete的狀態(tài)。打印原生的KeyValue對(duì)象,可以使用KeyValue.toString()方法(前面介紹過(guò)該方法)。 同前面介紹的批量操作相類,您不能保證服務(wù)器端收到的Delete實(shí)例的順序。API可能會(huì)打亂它們的順序,進(jìn)行重排。如果您很在意一組Delete實(shí)例執(zhí)行的前后順序,您必須把它們分成小的隊(duì)列,按照您所期望的順序依次執(zhí)行它們。最壞的情況便是,您一條一條的進(jìn)行刪除操作。 示例3-13 批量刪除 List<Delete> Delete delete1 = delete1.setTimestamp(4); deletes.add(delete1); Delete delete2 = delete2.deleteColumn(Bytes.toBytes(“colfam1″), delete2.deleteColumns(Bytes.toBytes(“colfam2″), deletes.add(delete2); Delete delete3 = delete3.deleteFamily(Bytes.toBytes(“colfam1″)); delete3.deleteFamily(Bytes.toBytes(“colfam2″), deletes.add(delete3); table.delete(deletes); table.close(); 首先創(chuàng)建了一個(gè)Delete對(duì)象的列表,然后為它們?cè)O(shè)置timestamp,刪除一個(gè)指定的版本。然后刪除colfam2:qual3下等于或小于版本5的所有數(shù)據(jù)。delete3刪除row3下的整個(gè)colfam1,刪除colfam2下等于或舊于版本3的所有記錄。最后通過(guò)HTable執(zhí)行批量刪除。 下面給出了HBase刪除數(shù)據(jù)前后對(duì)應(yīng)的數(shù)據(jù): Before delete KV: KV: KV: KV: row1/colfam1:qual2/3/Put/vlen=4, KV: KV: KV: KV: KV: row1/colfam2:qual2/4/Put/vlen=4, KV: KV: KV: KV: KV: KV: KV: KV: KV: KV: KV: KV: KV: KV: KV: KV: KV: KV: KV: KV: KV: row3/colfam1:qual3/5/Put/vlen=4, KV: KV: KV: KV: KV: row3/colfam2:qual3/6/Put/vlen=4, KV: After delete KV: KV: KV: KV: row1/colfam2:qual3/5/Put/vlen=4, KV: KV: KV: KV: KV: row2/colfam1:qual3/5/Put/vlen=4, KV: KV: KV: KV: KV: KV: KV: KV: 可以執(zhí)行如下的代碼,打印出上述的結(jié)果: System.out.println(“KV: “, 現(xiàn)在您應(yīng)該很熟悉Bytes類的使用方法,特別是對(duì)KeyValue結(jié)構(gòu)的處理。KeyValue.toString()方法只會(huì)打印出key部分的值,而并不會(huì)打印出對(duì)應(yīng)的value值(因?yàn)?/SPAN>value值可以非常大)。在示例中,由于表中的value值,是我們自己插入的,我們知道它的長(zhǎng)度,因此可以放心用終端打印出來(lái),在您的應(yīng)用中,也可以用類似的辦法進(jìn)行調(diào)試。 如果從本書(shū)所配的代碼庫(kù)整體來(lái)看,您便會(huì)明白數(shù)據(jù)是如何入庫(kù)和讀取的。下面將討論批量刪除操作的出錯(cuò)處理。delete方法接收的一組Delete對(duì)象,當(dāng)服務(wù)器端刪除出錯(cuò)時(shí),將刪除出錯(cuò)的Delete對(duì)象依然通過(guò)該參數(shù)返回到客戶端。 示例3-14 從HBase上刪除錯(cuò)誤的記錄 Delete delete4 = delete4.deleteColumn(Bytes.toBytes(“BOGUS”), deletes.add(delete4); try { table.delete(deletes); } catch (Exception System.err.println(“Error: } table.close(); System.out.println(“Deletes for (Delete delete System.out.println(delete); } 首先創(chuàng)建一個(gè)指向一個(gè)不存在列的Delete對(duì)象,然后在刪除該對(duì)象時(shí),會(huì)得到一個(gè)異常。查看返回的List的大小,然后打印出刪除出錯(cuò)的Delete對(duì)象。 示例3-14在示例3-13的基礎(chǔ)上添加了一個(gè)出錯(cuò)的delete對(duì)象,可以得到類似3-13的輸出結(jié)果,但會(huì)有幾條增加的輸出: Before delete KV: KV: … KV: KV: Error: Failed servers Deletes length: 1 row=row2, ts=9223372036854775807, (row2/BOGUS:qual1/9223372036854775807/Delete/vlen=0)} After delete KV: KV: … KV: row3/colfam2:qual3/6/Put/vlen=4, KV: 正如所期望的一樣,隊(duì)列會(huì)返回一個(gè)Delete實(shí)例,并指向“BOGUS”對(duì)應(yīng)的column family。我們使用toString()方法打印出出錯(cuò)的一行。Family名字是出錯(cuò)的根本原因。您在應(yīng)用程序中也可以使用這種方法來(lái)判斷刪除操作出錯(cuò)的行,一般情況下,刪除出錯(cuò)都是因?yàn)檫@個(gè)原因。 最后,出錯(cuò)拋出的異常和前面例子中的異常類似,RetriesExhaustedWithDetailsException已經(jīng)是第二次看到了。它打印出了出錯(cuò)時(shí)重做的次數(shù)。后面的章節(jié)將會(huì)講到如何監(jiān)控monitor server,因此,異常中返回的服務(wù)器IP是非常有用的。 在前面的“原子性的compare-and-set”一節(jié)中,講到了如使用原子性的比較、插入數(shù)據(jù)到HBase中的表中。對(duì)于刪除操作也給出了一個(gè)類似的方法,以原子的形式,在服務(wù)器端進(jìn)行比較,滿足條件后進(jìn)行刪除: boolean byte[] 上述方法需要指定rowkey、column family、qualifier和value來(lái)檢查,如果有滿足條件的值,則執(zhí)行delete。如果檢查失敗,則delete不執(zhí)行。當(dāng)delete成功執(zhí)行后返回true。示例3-15給出了一個(gè)使用的例子: 示例3-15 原子例的compare-and-set刪除操作 Delete delete1 = delete1.deleteColumns(Bytes.toBytes(“colfam1″), boolean res1 = Bytes.toBytes(“colfam2″), System.out.println(“Delete Delete delete2 = delete2.deleteColumns(Bytes.toBytes(“colfam2″), table.delete(delete2); boolean res2 = table.checkAndDelete(Bytes.toBytes(“row1″), Bytes.toBytes(“colfam2″), System.out.println(“Delete Delete delete3 = delete3.deleteFamily(Bytes.toBytes(“colfam1″)); try{ boolean Bytes.toBytes(“colfam1″), Bytes.toBytes(“val1″), System.out.println(“Delete } catch (Exception System.err.println(“Error: } 首先創(chuàng)建了一個(gè)Delete實(shí)例,指向row1對(duì)應(yīng)的colfam1:qual3列。然后檢查是否存在rowkey為row1,具含有colfam2:qual3列,不存該列,則執(zhí)行Delete實(shí)例,并打印出執(zhí)行的結(jié)果。由于檢查的列是存在的,運(yùn)行會(huì)打印出來(lái)“Delete Before delete KV: KV: KV: KV: KV: row1/colfam1:qual3/6/Put/vlen=4, KV: KV: KV: KV: KV: row1/colfam2:qual2/3/Put/vlen=4, KV: KV: Delete successful: Delete successful: After delete KV: KV: row1/colfam1:qual1/1/Put/vlen=4, KV: KV: KV: KV: KV: row1/colfam2:qual2/4/Put/vlen=4, KV: Error: org.apache.hadoop.hbase.DoNotRetryIOException: Action’s getRow … 使用null作為check操作的value,值不存在則check成功。由于在執(zhí)行前check的值已經(jīng)存在了,所以第一次check返回了false,delete操作未執(zhí)行。而后手工刪除了要check的值,再執(zhí)行checkAndDelete時(shí),check成功,delete操作被成功執(zhí)行。 這和前面介紹的put操作對(duì)應(yīng)的CAS調(diào)用是一樣的,您只能在同一行上執(zhí)行check-and-modify操作,若行不一致,將會(huì)拋出一個(gè)異常。當(dāng)然,check-and-modify操作允許check和modify操作的是同一行中兩個(gè)不同的column family。 示例沒(méi)有說(shuō)明check-and-modify操作有多么重要,在分布式系統(tǒng)中,在不加鎖、不損失性能的情況下保證操作的可靠性和原子性是很難的。因此,客戶端使用了一個(gè)排它鎖占有整個(gè)行。若客戶端在加鎖的階段出現(xiàn)了故障了,集群必須要保證被加鎖的行要重新unlock。在check-and-modify操作時(shí),會(huì)出現(xiàn)額外的RPC調(diào)用,因此,肯定會(huì)比單獨(dú)的服務(wù)器端操作慢一些。 |
|