1.插入数据
这次我们不需要去拿admin,因为我们不是管理表,而是直接对表进行操作
我们在拿到表之后如果想插入数据的话,要么插入一个put对象,要么插入一个put的list
而put是对我们需要放进的数据的封装
插入一行数据:
/**
* 插入一行数据
* @throws IOException
*/
@Test
public void testPut() throws IOException{
Table table = conn.getTable(TableName.valueOf("t_1"));
//put中的参数为行键
Put put = new Put("rk001".getBytes());
//参数依次为列族,key,value
//hbase提供了将各种数据转换为byte的方法Bytes.toBytes()
put.addColumn("f1".getBytes(), "uid".getBytes(), Bytes.toBytes(1));
put.addColumn("f1".getBytes(), "uname".getBytes(), Bytes.toBytes("zhangsan"));
put.addColumn("f1".getBytes(), "uage".getBytes(), Bytes.toBytes(18));
table.put(put);
table.close();
conn.close();
}
成功截图:
插入多行:
/**
* 插入多行数据
* @throws IOException
*/
@Test
public void testPuts() throws IOException{
Table table = conn.getTable(TableName.valueOf("t_1"));
Put put = new Put("rk001".getBytes());
put.addColumn("f1".getBytes(), "sex".getBytes(), Bytes.toBytes("male"));
put.addColumn("f1".getBytes(),"address".getBytes(),Bytes.toBytes("taiyuan") );
Put put2 = new Put("rk002".getBytes());
put2.addColumn("f2".getBytes(),"uid".getBytes() , Bytes.toBytes(2));
put2.addColumn("f2".getBytes(), "uname".getBytes(),Bytes.toBytes("zhangs4"));
ArrayList<Put> list = new ArrayList<Put>();
list.add(put);
list.add(put2);
table.put(list);
table.close();
conn.close();
}
成功截图:
上面生成的乱码其实是对整数进行编码之后的结果。
更新数据:
更新数据的本质就是重新构造一个相同key,但value不同的put对象,插入数据库
/**
* 更新数据
* @throws IOException
*/
@Test
public void testUpdate() throws IOException{
Table table = conn.getTable(TableName.valueOf("t_1"));
Put put = new Put("rk002".getBytes());
put.addColumn("f2".getBytes(), "uname".getBytes(), Bytes.toBytes("zhang5"));
table.put(put);
table.close();
conn.close();
}
成功截图:
删除数据:
删除一行中的某个值:
@Test
public void testDelete() throws IOException{
Table table = conn.getTable(TableName.valueOf("t_1"));
Delete delete = new Delete("rk001".getBytes());
delete.addColumn("f1".getBytes(), "uname".getBytes());
Delete delete2 = new Delete("rk002".getBytes());
delete2.addColumn("f2".getBytes(), "uname".getBytes());
ArrayList<Delete> list = new ArrayList<Delete>();
list.add(delete);
list.add(delete2);
table.delete(list);
}
成功截图:
我们可以看见删除之后数据不见了,而且还有一个地方值得注意,就是我们之前更新过的值,被删除之后回退到原来的版本 。
删除整行:
删除整行只需要指定行键即可
@Test
public void testDelete2() throws IOException{
Table table = conn.getTable(TableName.valueOf("t_1"));
Delete delete = new Delete("rk001".getBytes());
table.delete(delete);
}
成功截图:
对一行进行查询:
我们如果使用下面这种方式的话会有问题:
会出现乱码如下:
原因是什么?
原因就是无论我们使用getFamilyArray(),还是getQualifierArray(),他都会将那一个单元格的数据二进制数据都给我们,并不是说我们要哪个就给我们返回哪个字段。而且里面还带的一些二进制数据自带的分隔符。所以我们可以指定某个字段的起始偏移量和终止偏移量。那么他们为什么要这样做呢?就是因为开发者没有封装好,本身就是非常底层的东西。
我们可以像下面这样操作。
运行结果如下:
看到箭头指向的那个值仍为乱码,这是因为当初传值的时候传进去的是int值,而我们的value值的类型如果是多样的,这样就会造成麻烦,还需要进一步的判断。所以为了避免这种麻烦,我们最好当初传值的时候都传String,这样我们可以将String转换为我们需要的类型。就会方便很多。
以下贴出代码:
package com.test.hbase;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellScanner;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Before;
import org.junit.Test;
public class HbaseClientQuery {
Connection conn = null;
@Before
public void init() throws IOException{
Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum","marshal:2181,marshal01:2181,marshal02:2181,marshal03:2181,marshal04:2181,marshal05:2181" );
conn = ConnectionFactory.createConnection(conf);
}
/**
* 对一行进行查询
* @throws IOException
*/
@Test
public void testGet() throws IOException{
Table table = conn.getTable(TableName.valueOf("t_1"));
Get get = new Get("rk002".getBytes());
Result result = table.get(get);
/**
* 从返回结果中去除指定key的value
*/
//这里返回的是一个字节数组中,因为他也不知道你存储的是什么类型
byte[] value = result.getValue("f2".getBytes(), "uid".getBytes());
//我们有工具实现转型
int uid = Bytes.toInt(value);
System.out.println(uid);
//取出返回结果中所有key和value
//一对key,value相当于一个cell,这个scanner相当于一个迭代器
CellScanner cellScanner = result.cellScanner();
while(cellScanner.advance()){
Cell current = cellScanner.current();
byte[] rowArray = current.getRowArray();
String rowkey = Bytes.toString(rowArray,current.getRowOffset(),current.getRowLength());
byte[] familyArray = current.getFamilyArray();
String f = Bytes.toString(familyArray,current.getFamilyOffset(),current.getFamilyLength());
byte[] qualifierArray = current.getQualifierArray();
String q = Bytes.toString(qualifierArray,current.getQualifierOffset(),current.getQualifierLength());
byte[] valueArray = current.getValueArray();
String v = Bytes.toString(valueArray,current.getValueOffset(),current.getValueLength());
System.out.println(rowkey+","+f+":"+q+","+v);
}
table.close();
conn.close();
}
}
这样只能拿到一行的数据,如果我们想拿到多行的话,我们可以多new几个Get然后放入list中。
然后使用table.get(list);获取,这样就能拿到多行。
但是这样实际上还是一行一行去取的,我们还有一种便捷的方式:就是scan取多行
Scan可以指定起始行,还有结束行。如果不指定就是全表查询。但是最好不要这样做。因为hbase的表特别大。动不动就是几万亿行。
而且Scan还带过滤器,可以加一下条件过滤,不然数据真的太多了。
先看看我们表中的数据:
以下贴出代码:
public void printResult(Result result) throws IOException {
CellScanner cellScanner = result.cellScanner();
while(cellScanner.advance()){
Cell current = cellScanner.current();
byte[] rowArray = current.getRowArray();
String rowkey = Bytes.toString(rowArray,current.getRowOffset(),current.getRowLength());
byte[] familyArray = current.getFamilyArray();
String f = Bytes.toString(familyArray,current.getFamilyOffset(),current.getFamilyLength());
byte[] qualifierArray = current.getQualifierArray();
String q = Bytes.toString(qualifierArray,current.getQualifierOffset(),current.getQualifierLength());
byte[] valueArray = current.getValueArray();
String v = Bytes.toString(valueArray,current.getValueOffset(),current.getValueLength());
System.out.println(rowkey+","+f+":"+q+","+v);
}
}
@Test
public void testScan() throws IOException{
Table table = conn.getTable(TableName.valueOf("t_1"));
//扫描范围 含首不含尾
Scan scan = new Scan("rk001".getBytes(),"rk004".getBytes());
ResultScanner scanner = table.getScanner(scan);
Iterator<Result> iterator = scanner.iterator();
while(iterator.hasNext()){
Result next = iterator.next();
printResult(next);
}
table.close();
conn.close();
}
成功截图:
那么假如说有这样的场景:
我们的数据是这样的:
我们希望取到rk005,可是
因为使用扫描方法的话含首不含尾,我们又不知道rk005的下一个有几个0我们就可以使用八进制的0或者16进制的0
代码如下:
Scan scan = new Scan("rk001".getBytes(),("rk005"+"\000").getBytes());
Scan加过滤器:
我们如果加过滤器的话,scan方法就只有两个参数啦,一个是起始行,另一个是过滤器。
过滤器分为:行过滤器,列族过滤器,列过滤器,值过滤器。
过滤器也需要我们自己去创建 ,他有两个参数,第一个是比较逻辑有大于,小于,大于等于,小于等于。
第二个是ByteArrayComparable类型的比较器,他有以下类型:
代码如下:
@Test
public void testScanFilter() throws IOException{
Table table = conn.getTable(TableName.valueOf("t_1"));
RowFilter filter1 = new RowFilter(CompareOp.GREATER, new BinaryComparator("rk004".getBytes()));
RowFilter filter2 = new RowFilter(CompareOp.EQUAL, new BinaryPrefixComparator("rk".getBytes()));
FamilyFilter filter3 = new FamilyFilter(CompareOp.EQUAL, new BinaryComparator("f2".getBytes()));
QualifierFilter filter4 = new QualifierFilter(CompareOp.EQUAL, new BinaryComparator("uid".getBytes()));
ValueFilter filter5 = new ValueFilter(CompareOp.EQUAL, new BinaryComparator("1".getBytes()));
Scan scan = new Scan("rk001".getBytes(),filter5);
ResultScanner scanner = table.getScanner(scan);
Iterator<Result> iterator = scanner.iterator();
while(iterator.hasNext()){
Result next = iterator.next();
printResult(next);
}
table.close();
conn.close();
}