-
put没什么特别需要注意的,如下代码
public void putData() throws IOException {
Connection connection = ConnectionFactory.createConnection();
Table table = connection.getTable(TableName.valueOf("default:test"));
//创建put对象,一个put肯定要对应一行的,所以参数是必须的,但是有重载的参数,自己可以去看一下
Put putObj = new Put("row1".getBytes());
//上面行指定完后,就需要指定列族,列,值,这样才是完整的
putObj.addColumn("cf".getBytes(), "name".getBytes(), "wangziqiang".getBytes());
//执行~
table.put(putObj);
connection.close();
table.close();
}
- 我们发现一直到现在我们写过的api中,都是
xx.getBytes()显得很麻烦,那么有什么办法解决吗?还真..没有,既然不能解决,HBase就自带了一个Bytes类,使用也很简单就是Bytes.toXXX(ss)就可以了,这也说明了HBase中所有数据都是bytes数组,一切可以序列化为bytes的对象都可以作为rowkey,所以你就可以使用任何的序列化工具来保存在HBase中,比如Avro之类的
-
Put类每次调用addColumn都会返回Put,所以我们就可以使用Builder模式来写代码了,如下
putObj.addColumn(xx)
.addColumn(xx)
.addColumn(xx);
- 但是如果在你读出数据之后和修改数据中间这段时间,如果有别人也修改了这个数据,就会发生数据不一致的问题,因为你后添加的数据将会更新掉人家添加的那个数据,那么我们怎么确保这期间不会有人插足,成为第三者呢?
-
checkAndMutate方法只是把检查和写入这两个步骤合二为一了.checkAndMutate方法在写入 前会先比较目前存在的数据是否与你传入的数据一致,如果一致则进行 put操作,并返回true.如果不一致,则返回false,但不写入数据(原子操作).那我们试试,首先HBase中的数据我并没有改,依旧是上面插入的wangziqiang,然后我们编写代码
public void checkAndPut() throws IOException {
Connection connection = ConnectionFactory.createConnection();
Table table = connection.getTable(TableName.valueOf("test"));
Put putObj = new Put("row1".getBytes());
putObj.addColumn("cf".getBytes(), "name".getBytes(), "wzq".getBytes());
//如果你对链式编程很熟悉,那么下面会很简单
//猜测thenPut方法是一个"触发方法",因为java的stream就是这样的
//指定行和列族
boolean b = table.checkAndMutate("row1".getBytes(), "cf".getBytes())
//指定列
.qualifier("name".getBytes())
//判断是否与这个串相等
.ifEquals("wangziqiang".getBytes())
//相等就put返回true,否则不put返回false
.thenPut(putObj);
System.out.println(b);
table.close();
connection.close();
}
-
在跑之前,我们将name值用shell改掉,看看他是否还是会put
hbase(main):022:0> scan 'test'
ROW COLUMN+CELL
row1 column=cf:name, timestamp=1543680836035, value=xgl
1 row(s)
Took 0.0130 seconds
-
执行结果就是false,当我们在手动改回去的时候,再次执行,就会返回true,不仅仅只能判断是否相等,还可以有比较器啊,或者删除操作,那么比较器是怎么用呢?
boolean b = table.checkAndMutate("row1".getBytes(), "cf".getBytes())
//指定列
.qualifier("name".getBytes())
//判断是否比1小
.ifMatches(CompareOperator.LESS, Bytes.toBytes(1))
//相等就put返回true,否则不put返回false
.thenPut(putObj);
-
对于枚举类可选参数有如下
/** less than */
LESS,
/** less than or equal to */
LESS_OR_EQUAL,
/** equals */
EQUAL,
/** not equal */
NOT_EQUAL,
/** greater than or equal to */
GREATER_OR_EQUAL,
/** greater than */
GREATER,
/** no operation */
NO_OP,
-
get方法跟shell作用的一样的,那么我们就可以得到一个版本的cell,或者全部版本的cell,如下
public void getData() throws IOException {
Connection connection = ConnectionFactory.createConnection();
Table table = connection.getTable(TableName.valueOf("default:test"));
//指定行
Get getObj = new Get("row1".getBytes());
//根据行查询出行中信息,封装为result对象
Result result = table.get(getObj);
for (Cell cell : result.listCells()) {
System.out.println(Bytes.toString(cell.getRowArray()));
System.out.println("family:" + Bytes.toString(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()));
System.out.println("qualifier:" + Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()));
System.out.println("value:" + Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()));
System.out.println("Timestamp:" + cell.getTimestamp());
}
table.close();
connection.close();
}
-
执行结果
row1cfage gl��20
family:cf
qualifier:age
value:20
Timestamp:1543706228633
row1cfname glj;wangziqiang
family:cf
qualifier:name
value:wangziqiang
Timestamp:1543706208827
- 你没看错,结果就有的是类似乱码,但这只是编码显示不了而已,我在这卡主了半天,硬是没想到偏移量,在查看帮助后才修改过来,所以自学是真的有点苦逼的哈哈 ,我们看上面的输出语句和对照下面的输出就能看到这个get是怎么用的,我猜那些个乱码应该是标识下一个数据长度的这么一个东西,不过只是猜测,之后肯定会有一个HBase的File或者Cell结构,我们就清楚了,现在不用了解很多,而且我也不会哈哈
- 网上有人说str.toBytes可能会有风险,我也不清楚,不过写在这里也是告诉大家一下,毕竟HBase提供了工具类Bytes
-
当然上面的代码中getObj也可以添加列条件,比如
...
Get getObj = new Get("row1".getBytes());
getObj.addColumn(Bytes.toBytes("cf"),Bytes.toBytes("name"));
...
-
那么执行结果就只是有name的cell了,到这我们只是返回了一个版本的cell,我们之前可是put了很多的name的,那么如何查看这些信息呢?
//代码几乎是一致的,只是将get对象设置一个属性即可
public void getData() throws IOException {
....
//指定行
Get getObj = new Get("row1".getBytes());
getObj.readVersions(5); //变化!!!!
//根据行查询出行中信息,封装为result对象
Result result = table.get(getObj);
for (Cell cell : result.getColumnCells(Bytes.toBytes("cf"),Bytes.toBytes("name"))) {
System.out.println(Bytes.toString(cell.getValueArray()));
System.out.println(Bytes.toString(CellUtil.cloneValue(cell)));
}
...
}
- 好了这就是查看历史cell的方法,如果你没有运行出结果来,而仅仅是一条,那么你就应该想到你的表是否多次添加过相同cell的数据,并且他的VERSIONS属性是设置正确的
-
上面有两个输出,他们是这样的
row1cfname glK�wangziqiang
wangziqiang
- 第一个输出是直接getXXvalue的方法获取的,他将完整的信息全部都拿到了,而下面的clone方法,仅仅是我们需要的数据,所以在使用cell上优先使用第二种