HBase常用操作

目录:

引言 -- 参数基础

1. 结构(Structural)过滤器--FilterList

2.列值过滤器--SingleColumnValueFilter

2.1.第一种构造函数情况 -- 比较的关键字是字符数组

2.2.第二种构造函数情况 -- 比较的关键字是比较器ByteArrayComparable

3.键值元数据

3.1. 基于列族过滤数据的FamilyFilter

3.2. 基于限定符Qualifier(列)过滤数据的QualifierFilter

3.3. 基于列名(即Qualifier)前缀过滤数据的ColumnPrefixFilter

3.4. 基于多个列名(即Qualifier)前缀过滤数据的MultipleColumnPrefixFilter

3.5. 基于列范围(不是行范围)过滤数据ColumnRangeFilter

4. RowKey

5. PageFilter

6. SkipFilter

7. Utility--FirstKeyOnlyFilter

8. 取得查询结果

引言 -- 参数基础

有两个参数类在各类Filter中经常出现,统一介绍下:

(1)比较运算符 CompareFilter.CompareOp

比较运算符用于定义比较关系,可以有以下几类值供选择:

EQUAL                                  相等

GREATER                              大于

GREATER_OR_EQUAL          大于等于

LESS                                      小于

LESS_OR_EQUAL                  小于等于

NOT_EQUAL                        不等于

(2)比较器  ByteArrayComparable

通过比较器可以实现多样化目标匹配效果,比较器有以下子类可以使用:

BinaryComparator              匹配完整字节数组

BinaryPrefixComparator    匹配字节数组前缀

BitComparator

NullComparator

RegexStringComparator    正则表达式匹配

SubstringComparator        子串匹配

1. 结构(Structural)过滤器--FilterList

FilterList 代表一个过滤器链,它可以包含一组即将应用于目标数据集的过滤器,过滤器间具有“与” FilterList.Operator.MUST_PASS_ALL 和“或” FilterList.Operator.MUST_PASS_ONE 关系。

官网实例代码,两个“或”关系的过滤器的写法:

FilterList list = new FilterList(FilterList.Operator.MUST_PASS_ONE);  //数据只要满足一组过滤器中的一个就可以

SingleColumnValueFilter filter1 = new SingleColumnValueFilter(

cf,

column,

CompareOp.EQUAL,

Bytes.toBytes("my value")

);

list.add(filter1);

SingleColumnValueFilter filter2 = new SingleColumnValueFilter(

cf,

column,

CompareOp.EQUAL,

Bytes.toBytes("my other value")

);

list.add(filter2);

Scan scan = new Scan();

scan.setFilter(list);

2. 列值过滤器--SingleColumnValueFilter

SingleColumnValueFilter 用于测试列值相等 (CompareOp.EQUAL ), 不等 (CompareOp.NOT_EQUAL),或单侧范围 (e.g., CompareOp.GREATER)。

构造函数:

(1)比较的关键字是一个字符数组

SingleColumnValueFilter(byte[] family, byte[] qualifier, CompareFilter.CompareOp compareOp, byte[] value)

(2)比较的关键字是一个比较器(比较器下一小节做介绍)

SingleColumnValueFilter(byte[] family, byte[] qualifier, CompareFilter.CompareOp compareOp, ByteArrayComparable comparator)

2.1.第一种构造函数情况 -- 比较的关键字是字符数组

官网示例代码,检查列值和字符串'my value' 相等:

SingleColumnValueFilter filter = new SingleColumnValueFilter(

cf,

column,

CompareOp.EQUAL,

Bytes.toBytes("my value")

);

scan.setFilter(filter);

个人实测代码:

HTable table = HBaseDAO.getHTable("147patents");

FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);

SingleColumnValueFilter filter = new SingleColumnValueFilter(

Bytes.toBytes("patentinfo"),

Bytes.toBytes("CREATE_TIME"),

CompareOp.EQUAL,

Bytes.toBytes("2013-06-08")

);

filterList.addFilter(filter);

Scan scan = new Scan();

scan.setFilter(filterList);

ResultScanner rs = table.getScanner(scan);

for (Result r : rs) {

System.out.println("Scan: " + r);

}

table.close();

注意:还是大写问题,HBase的列名必须大写!

2.2.第二种构造函数情况 -- 比较的关键字是比较器ByteArrayComparable

该章节主要是针对SingleColumnValueFilter的第二种构造函数使用情况做了一些举例:

(1)支持值比较的正则表达式 -- RegexStringComparator

官网示例代码:

RegexStringComparator comp = new RegexStringComparator("my.");  //任意以my打头的值

SingleColumnValueFilter filter = new SingleColumnValueFilter(

cf,

column,

CompareOp.EQUAL,

comp

);

scan.setFilter(filter);

个人实测代码:

HTable table = HBaseDAO.getHTable("147patents");

FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);

RegexStringComparator comp = new RegexStringComparator("2013-06-1.");

SingleColumnValueFilter filter = new SingleColumnValueFilter(

Bytes.toBytes("patentinfo"),

Bytes.toBytes("CREATE_TIME"),

CompareOp.EQUAL,

comp

);

filterList.addFilter(filter);

Scan scan = new Scan();

scan.setFilter(filterList);

ResultScanner rs = table.getScanner(scan);

for (Result r : rs) {

System.out.println("Scan: " + r);

}

table.close();

(2)检测一个子串是否存在于值中(大小写不敏感) -- SubstringComparator

官网示例代码:

SubstringComparator comp = new SubstringComparator("y val");  // looking for 'my value'

SingleColumnValueFilter filter = new SingleColumnValueFilter(

cf,

column,

CompareOp.EQUAL,

comp

);

scan.setFilter(filter);

个人实测代码:

HTable table = HBaseDAO.getHTable("147patents");

FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);

//        RegexStringComparator comp = new RegexStringComparator("2013-06-1.");

SubstringComparator comp = new SubstringComparator("2013-06-1");

SingleColumnValueFilter filter = new SingleColumnValueFilter(

Bytes.toBytes("patentinfo"),

Bytes.toBytes("CREATE_TIME"),

CompareOp.EQUAL,

comp

);

filterList.addFilter(filter);

Scan scan = new Scan();

scan.setFilter(filterList);

ResultScanner rs = table.getScanner(scan);

for (Result r : rs) {

System.out.println("Scan: " + r);

}

table.close();

(3)BinaryComparator

二进制比较器,用得较少,有需要请自行查阅官网:http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/BinaryComparator.html

(4)BinaryPrefixComparator

二进制前缀比较器,用得较少,有需要请自行查阅官网:http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/BinaryPrefixComparator.html

3. 键值元数据

由于HBase 采用键值对保存内部数据,键值元数据过滤器评估一行的键(ColumnFamily:Qualifiers)是否存在 , 对应前节所述值的情况。

3.1. 基于列族过滤数据的FamilyFilter

构造函数:

FamilyFilter(CompareFilter.CompareOp familyCompareOp, ByteArrayComparable familyComparator)

个人实测代码:

HTable table = HBaseDAO.getHTable("147patents");

/**

* FamilyFilter构造函数中第二个参数是ByteArrayComparable类型

* ByteArrayComparable类参见“引言-参数基础”章节

* 下面仅以最可能用到的BinaryComparator、BinaryPrefixComparator举例:

*/

FamilyFilter ff = new FamilyFilter(

CompareFilter.CompareOp.EQUAL ,

new BinaryComparator(Bytes.toBytes("pat"))  //表中不存在pat列族,过滤结果为空

);

FamilyFilter ff1 = new FamilyFilter(

CompareFilter.CompareOp.EQUAL ,

new BinaryPrefixComparator(Bytes.toBytes("pat"))  //表中存在以pat打头的列族patentinfo,过滤结果为该列族所有行

);

Scan scan = new Scan();

scan.setFilter(ff1);

ResultScanner rs = table.getScanner(scan);

注意:

如果希望查找的是一个已知的列族,则使用 scan.addFamily(family)  比使用过滤器效率更高;

由于目前HBase对多列族支持不完善,所以该过滤器目前用途不大。

3.2. 基于限定符Qualifier(列)过滤数据的QualifierFilter

构造函数:

QualifierFilter(CompareFilter.CompareOp op, ByteArrayComparable qualifierComparator)

个人实测代码:

HTable table = HBaseDAO.getHTable("147patents");

/**

* QualifierFilter构造函数中第二个参数是ByteArrayComparable类型

* ByteArrayComparable类有以下子类可以使用:

* *******************************************

* BinaryComparator  匹配完整字节数组,

* BinaryPrefixComparator  匹配开始的部分字节数组,

* BitComparator,

* NullComparator,

* RegexStringComparator,  正则表达式匹配

* SubstringComparator

* *******************************************

* 下面仅以最可能用到的BinaryComparator、BinaryPrefixComparator举例:

*/

QualifierFilter ff = new QualifierFilter(

CompareFilter.CompareOp.EQUAL ,

new BinaryComparator(Bytes.toBytes("belong"))  //表中不存在belong列,过滤结果为空

);

QualifierFilter ff1 = new QualifierFilter(

CompareFilter.CompareOp.EQUAL ,

new BinaryPrefixComparator(Bytes.toBytes("BELONG"))  //表中存在以BELONG打头的列BELONG_SITE,过滤结果为所有行的该列数据

);

Scan scan = new Scan();

scan.setFilter(ff1);

ResultScanner rs = table.getScanner(scan);

说明:

一旦涉及到列(Qualifier),HBase就只认大写字母了!

该过滤器应该比FamilyFilter更常用!

3.3. 基于列名(即Qualifier)前缀过滤数据的ColumnPrefixFilter  ( 该功能用QualifierFilter也能实现 )

构造函数:

ColumnPrefixFilter(byte[] prefix)

注意:

一个列名是可以出现在多个列族中的,该过滤器将返回所有列族中匹配的列。

官网示例代码,查找所有"abc"打头的列:

HTableInterface t = ...;

byte[] row = ...;

byte[] family = ...;

byte[] prefix = Bytes.toBytes("abc");

Scan scan = new Scan(row, row); // (optional) limit to one row

scan.addFamily(family); // (optional) limit to one family

Filter f = new ColumnPrefixFilter(prefix);

scan.setFilter(f);

scan.setBatch(10); // set this if there could be many columns returned

ResultScanner rs = t.getScanner(scan);

for (Result r = rs.next(); r != null; r = rs.next()) {

for (KeyValue kv : r.raw()) {

// each kv represents a column

}

}

rs.close();

个人实测代码:

HTable table = HBaseDAO.getHTable("147patents");

//返回所有行中以BELONG打头的列的数据

ColumnPrefixFilter ff1 = new ColumnPrefixFilter(Bytes.toBytes("BELONG"));

Scan scan = new Scan();

scan.setFilter(ff1);

ResultScanner rs = table.getScanner(scan);

3.4. 基于多个列名(即Qualifier)前缀过滤数据的MultipleColumnPrefixFilter

说明:

MultipleColumnPrefixFilter 和 ColumnPrefixFilter 行为差不多,但可以指定多个前缀。

官方示例代码,查找所有"abc"或"xyz"打头的列:

HTableInterface t = ...;

byte[] row = ...;

byte[] family = ...;

byte[][] prefixes = new byte[][] {Bytes.toBytes("abc"), Bytes.toBytes("xyz")};

Scan scan = new Scan(row, row); // (optional) limit to one row

scan.addFamily(family); // (optional) limit to one family

Filter f = new MultipleColumnPrefixFilter(prefixes);

scan.setFilter(f);

scan.setBatch(10); // set this if there could be many columns returned

ResultScanner rs = t.getScanner(scan);

for (Result r = rs.next(); r != null; r = rs.next()) {

for (KeyValue kv : r.raw()) {

// each kv represents a column

}

}

rs.close();

个人实测代码:

HTable table = HBaseDAO.getHTable("147patents");

byte[][] prefixes = new byte[][] {Bytes.toBytes("BELONG"), Bytes.toBytes("CREATE")};

//返回所有行中以BELONG或者CREATE打头的列的数据

MultipleColumnPrefixFilter ff = new MultipleColumnPrefixFilter(prefixes);

Scan scan = new Scan();

scan.setFilter(ff);

ResultScanner rs = table.getScanner(scan);

3.5. 基于列范围(不是行范围)过滤数据ColumnRangeFilter

说明:

可用于获得一个范围的列,例如,如果你的一行中有百万个列,但是你只希望查看列名为bbbb到dddd的范围

该方法从 HBase 0.92 版本开始引入

一个列名是可以出现在多个列族中的,该过滤器将返回所有列族中匹配的列

构造函数:

ColumnRangeFilter(byte[] minColumn, boolean minColumnInclusive, byte[] maxColumn, boolean maxColumnInclusive)

参数解释:

minColumn - 列范围的最小值,如果为空,则没有下限;

minColumnInclusive - 列范围是否包含minColumn ;

maxColumn - 列范围最大值,如果为空,则没有上限;

maxColumnInclusive - 列范围是否包含maxColumn 。

官网示例代码,查找列名在"bbbb"到"dddd"范围的数据:

HTableInterface t = ...;

byte[] row = ...;

byte[] family = ...;

byte[] startColumn = Bytes.toBytes("bbbb");

byte[] endColumn = Bytes.toBytes("bbdd");

Scan scan = new Scan(row, row); // (optional) limit to one row

scan.addFamily(family); // (optional) limit to one family

Filter f = new ColumnRangeFilter(startColumn, true, endColumn, true);

scan.setFilter(f);

scan.setBatch(10); // set this if there could be many columns returned

ResultScanner rs = t.getScanner(scan);

for (Result r = rs.next(); r != null; r = rs.next()) {

for (KeyValue kv : r.raw()) {

// each kv represents a column

}

}

rs.close();

个人实测代码:

HTable table = HBaseDAO.getHTable("147patents");

byte[] startColumn = Bytes.toBytes("C");

byte[] endColumn = Bytes.toBytes("D");

//返回所有列中从C到D打头的范围的数据,实际返回类似CREATOR、CREATE_TIME、CHANNEL_CODE等列的数据

ColumnRangeFilter ff = new ColumnRangeFilter(startColumn, true, endColumn, true);

Scan scan = new Scan();

scan.setFilter(ff);

ResultScanner rs = table.getScanner(scan);

4. RowKey

当需要根据行键特征查找一个范围的行数据时,使用Scan的startRow和stopRow会更高效,但是,startRow和stopRow只能匹配行键的开始字符,而不能匹配中间包含的字符:

byte[] startColumn = Bytes.toBytes("aaa");

byte[] endColumn = Bytes.toBytes("bbb");

Scan scan = new Scan(startColumn,endColumn);

当需要针对行键进行更复杂的过滤时,可以使用RowFilter:

构造函数:

RowFilter(CompareFilter.CompareOp rowCompareOp, ByteArrayComparable rowComparator)

参数解释参见“引言-参数基础”章节。

个人实测代码:

HTable table = HBaseDAO.getHTable("147patents");

/**

* rowkey格式为:创建日期_发布日期_ID_TITLE

* 目标:查找  发布日期  为  2013-07-16  的数据

*/

RowFilter rf = new RowFilter(

CompareFilter.CompareOp.EQUAL ,

new SubstringComparator("_2013-07-16_")

);

Scan scan = new Scan();

scan.setFilter(rf);

ResultScanner rs = table.getScanner(scan);

注意:

测试过程中尝试通过组合使用两个RowFilter(CompareFilter.CompareOp参数分别为GREATER_OR_EQUAL和LESS_OR_EQUAL),和SubstringComparator,过滤找出指定发布时间范围内的数据,但结果比较意外,不是预想的数据,估计比较运算符GREATER_OR_EQUAL和LESS_OR_EQUAL和比较器SubstringComparator组合使用效果不太好,慎用。

5.PageFilter

指定页面行数,返回对应行数的结果集。

需要注意的是,该过滤器并不能保证返回的结果行数小于等于指定的页面行数,因为过滤器是分别作用到各个region server的,它只能保证当前region返回的结果行数不超过指定页面行数。

构造函数:

PageFilter(long pageSize)

实测代码(从“2013-07-26”行开始,取5行):

Scan scan = new Scan();

scan.setStartRow(Bytes.toBytes("2013-07-26"));

PageFilter pf = new PageFilter(5L);

scan.setFilter(pf);

ResultScanner rs = table.getScanner(scan);

for (Result r : rs) {

for (Cell cell : r.rawCells()) {

System.out.println("Rowkey : " + Bytes.toString(r.getRow())

+ "  Familiy:Quilifier : "

+ Bytes.toString(CellUtil.cloneQualifier(cell))

+ "  Value : "

+ Bytes.toString(CellUtil.cloneValue(cell))

+ "  Time : " + cell.getTimestamp());

}

}

注意:

由于该过滤器并不能保证返回的结果行数小于等于指定的页面行数,所以更好的返回指定行数的办法是ResultScanner.next(int nbRows) ,即:

ResultScanner rs = table.getScanner(scan);

for (Result r : rs.next(5)) {

for (Cell cell : r.rawCells()) {

System.out.println("Rowkey : " + Bytes.toString(r.getRow())

+ "  Familiy:Quilifier : "

+ Bytes.toString(CellUtil.cloneQualifier(cell))

+ "  Value : "

+ Bytes.toString(CellUtil.cloneValue(cell))

+ "  Time : " + cell.getTimestamp());

}

}

6.SkipFilter

根据整行中的每个列来做过滤,只要存在一列不满足条件,整行都被过滤掉。

例如,如果一行中的所有列代表的是不同物品的重量,则真实场景下这些数值都必须大于零,我们希望将那些包含任意列值为0的行都过滤掉。

在这个情况下,我们结合ValueFilter和SkipFilter共同实现该目的:

scan.setFilter(new SkipFilter(new ValueFilter(CompareOp.NOT_EQUAL,new BinaryComparator(Bytes.toBytes(0))));

构造函数:

SkipFilter(Filter filter)

个人实测代码:

目前的数据:

hbase(main):009:0> scan 'rd_ns:itable'

ROW                        COLUMN+CELL

100001                    column=info:address, timestamp=1405417403438, value=anywhere

100001                    column=info:age, timestamp=1405417403438, value=24

100001                    column=info:name, timestamp=1405417403438, value=zhangtao

100002                    column=info:address, timestamp=1405417426693, value=shangdi

100002                    column=info:age, timestamp=1405417426693, value=28

100002                    column=info:name, timestamp=1405417426693, value=shichao

100003                    column=info:address, timestamp=1405494141522, value=huilongguan

100003                    column=info:age, timestamp=1405494999631, value=29

100003                    column=info:name, timestamp=1405494141522, value=liyang

3 row(s) in 0.0190 seconds

执行以下代码:

Configuration conf = HBaseConfiguration.create();

HTable table = new HTable(conf, "rd_ns:itable");

Scan scan = new Scan();

scan.setFilter(new SkipFilter(new ValueFilter(CompareOp.NOT_EQUAL,

new BinaryComparator(Bytes.toBytes("28")))));

ResultScanner rs = table.getScanner(scan);

for (Result r : rs) {

for (Cell cell : r.rawCells()) {

System.out.println("Rowkey : " + Bytes.toString(r.getRow())

+ "  Familiy:Quilifier : "

+ Bytes.toString(CellUtil.cloneQualifier(cell))

+ "  Value : "

+ Bytes.toString(CellUtil.cloneValue(cell))

+ "  Time : " + cell.getTimestamp());

}

}

table.close();

输出结果(整个100002行被过滤掉了):

Rowkey : 100001  Familiy:Quilifier : address  Value : anywhere  Time : 1405417403438

Rowkey : 100001  Familiy:Quilifier : age  Value : 24  Time : 1405417403438

Rowkey : 100001  Familiy:Quilifier : name  Value : zhangtao  Time : 1405417403438

Rowkey : 100003  Familiy:Quilifier : address  Value : huilongguan  Time : 1405494141522

Rowkey : 100003  Familiy:Quilifier : age  Value : 29  Time : 1405494999631

Rowkey : 100003  Familiy:Quilifier : name  Value : liyang  Time : 1405494141522

7. Utility--FirstKeyOnlyFilter

该过滤器仅仅返回每一行中的第一个cell的值,可以用于高效的执行行数统计操作。

估计实战意义不大。

构造函数:

public FirstKeyOnlyFilter()

个人实测代码:

HTable table = HBaseDAO.getHTable("147patents");

FirstKeyOnlyFilter fkof = new FirstKeyOnlyFilter();

Scan scan = new Scan();

scan.setFilter(fkof);

ResultScanner rs = table.getScanner(scan);

8. 取得查询结果

无论是官网的Ref Guide还是网上流传的大部分博客中,输出查询结果的代码都是:

for (Result r = rs.next(); r != null; r = rs.next()) {

for (KeyValue kv : r.raw()) {

// each kv represents a column

}

}

但查看最新的API可知Result实例的raw()方法已经不建议使用了:

raw() Deprecated. as of 0.96, use rawCells()

0.96以后版本正确的获取结果代码如下:

for (Result r : rs) {

for (Cell cell : r.rawCells()) {

System.out.println(

"Rowkey : "+Bytes.toString(r.getRow())+

"Familiy:Quilifier : "+Bytes.toString(CellUtil.cloneQualifier(cell))+

"Value : "+Bytes.toString(CellUtil.cloneValue(cell))

);

}

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • http://blog.csdn.net/fengzheku/article/details/48447791 p...
    木子Qing阅读 2,524评论 1 1
  • 通过Java 操作Hbase 一、版本: hbase: 二、操作Hbase: 1、首先定义几个用的到的全局变量: ...
    利伊奥克儿阅读 1,635评论 0 6
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • 以往的生日,都没有写,我想往后的每个生日,都记录些什么来。 小学傻傻留级一年毕业,初中不得已转学回家升高中,高中后...
    柔软的时候阅读 215评论 0 0