分享

HBase表管理系统

本帖最后由 PeersLee 于 2016-5-25 12:27 编辑
问题导读:
1. 软件是什么版本和如何部署?
2.系统功能介绍及核心如何实现?
3.如何对表进行增删改查?




解决方案:

1. 软件版本 & 部署:

maven:3.3.9,jdk:1.7 ,Struts2:2.3.24.1,hibernate:4.3.6,spring:4.2.5,MySQL:5.1.34,Junit:4,Myeclipse:2014;

源码下载:https://github.com/fansy1990/ssh_v3/releases

部署参考:http://blog.csdn.net/fansy1990/article/details/51356583


2. 系统功能及核心实现
2.1系统菜单


2016-05-25_120159.png

HBase表管理系统主要是对表以及表数据的相关操作;

2.2 表管理

2016-05-25_120247.png

直接打开Table管理界面,即可看到所有表的简要信息,包括数据库(namspace)、表名、简单表描述等;

这个查询的信息直接基于Admin的listTableNames方法,具体调用如下:


[mw_shl_code=java,true]/**
         * 获取所有表
         *
         * @return
         * @throws IOException
         */
        public List<HBaseTable> getTables() throws IOException {
                List<HBaseTable> list = new ArrayList<>();
                Admin admin = HadoopUtils.getHBaseConnection().getAdmin();
                TableName[] tables = admin.listTableNames();
                HBaseTable hTable = null;

                for (TableName t : tables) {
                        hTable = new HBaseTable();
                        hTable.setNameSpace(t.getNamespaceAsString());
                        hTable.setTableName(t.getNameAsString());
                        // HTableDescriptor htableDes = admin.getTableDescriptor(t);
                        // System.out.println(htableDes.toString());
                        // System.out.println(htableDes.toStringTableAttributes());
                        // System.out.println(htableDes.getFamilies().toString());
                        // System.out.println(htableDes.toStringCustomizedValues());
                        hTable.setDescription(admin.getTableDescriptor(t)
                                        .toStringCustomizedValues());
                        setRegions(hTable, admin.getTableRegions(t));
                        list.add(hTable);
                }

                return list;
        }[/mw_shl_code]

2.2.1 表详细
表详细功能需要先选定一行记录,否则会提示:


2016-05-25_120719.png

选择一个记录后,点击表详细即可弹出表详细信息:

2016-05-25_120750.png

后台实现通过admin.getTableDescriptor即可获得表的详细信息,但是需要提供表名,表名可以从前天传入即可,如下:

[mw_shl_code=java,true]/**
         * 获取指定表详细信息
         *
         * @param tableName
         * @return
         * @throws IOException
         */
        public String getTableDetails(String tableName) throws IOException {
                Admin admin = HadoopUtils.getHBaseConnection().getAdmin();
                HTableDescriptor tableDescriptors = admin
                                .getTableDescriptor(getTableName(tableName));
                System.out.println(tableDescriptors.toStringCustomizedValues());
                System.out.println(tableDescriptors.toString());
                return admin.getTableDescriptor(getTableName(tableName)).toString();
        }[/mw_shl_code]

2.2.2 表新增
表新增功能只是提供一个简单的新增,即只提供表名、列簇名即可,如下:


2016-05-25_120844.png

同时提交后台后,如果表已经存在则会进行对应的提示,后台通过遍历所有表名实现此功能,效率不高,实现如下:

[mw_shl_code=java,true]public boolean checkTableExists(String tableName) throws IOException {
                Admin admin = HadoopUtils.getHBaseConnection().getAdmin();
                TableName[] tables = admin.listTableNames();
                for (TableName t : tables) {
                        if (t.getNameAsString().equals(tableName)) {
                                return true;
                        }
                }
                return false;
        }[/mw_shl_code]

新增表,通过admin的createTable实现:

[mw_shl_code=java,true]public boolean saveTable(String tableName, String cfs) throws IOException {
                Admin admin = HadoopUtils.getHBaseConnection().getAdmin();
                HTableDescriptor hTableDescriptor = new HTableDescriptor(
                                getTableName(tableName));
                String[] cfsArr = StringUtils.split(cfs, Utils.COMMA);
                for (String cf : cfsArr) {
                        hTableDescriptor.addFamily(new HColumnDescriptor(cf));
                }
                admin.createTable(hTableDescriptor);
                return true;
        }[/mw_shl_code]

2.2.3 表删除
表删除,同样需要选择一条记录,如果没有选择记录,同样会提示选择表,选择表后,点击删除,会进行下面的提示:


2016-05-25_121017.png

如果点击OK,则删除,Cancel则取消;

删除实现,同样使用Admin的disableTable, deleteTable方法


[mw_shl_code=java,true]public boolean deleteTable(String tableName) throws IOException {
                Admin admin = HadoopUtils.getHBaseConnection().getAdmin();
                admin.disableTable(getTableName(tableName));
                admin.deleteTable(getTableName(tableName));
                return true;
        }[/mw_shl_code]

2.3 表数据管理

2016-05-25_121119.png

在打开表数据管理页面后,会初始化表名的下拉框,下拉框中数据的获取采用AJax的方式访问后台获取,方法同样使用Admin的listTableNames方法;

2016-05-25_121151.png

在选择一个表后,会初始化列簇名下拉框数据和start rowkey ,如下:

2016-05-25_121241.png

在查询数据时,可以选择多个列簇名,同时可以修改Start rowkey ,选择记录数以及版本数;

2016-05-25_121313.png

根据表名获取列簇名后台代码实现如下(通过HTableDescriptor的getColumnFamilies方法获取):

[mw_shl_code=java,true]public List<TextValue> getTablesColumnFamily(String tableName)
                        throws IOException {
                List<TextValue> list = new ArrayList<>();
                Admin admin = HadoopUtils.getHBaseConnection().getAdmin();
                HTableDescriptor tableDescriptor = admin
                                .getTableDescriptor(getTableName(tableName));
                HColumnDescriptor[] columnDescriptors = tableDescriptor
                                .getColumnFamilies();
                for (HColumnDescriptor t : columnDescriptors) {
                        list.add(new TextValue(t.getNameAsString()));
                }
                return list;
        }[/mw_shl_code]

以及start rowKey的后台代码如下(即,只读取第一行数据,然后返回其rowkey):

[mw_shl_code=java,true]public String getTableRowKey(String tableName) throws IOException {
                Table table = HadoopUtils.getHBaseConnection().getTable(
                                getTableName(tableName));
                Scan scan = new Scan();
                ResultScanner scanner = table.getScanner(scan);
                Result firstRow = scanner.next();
                scanner.close();
                table.close();
                if (firstRow == null)
                        return "-1";

                return new String(firstRow.getRow());
        }[/mw_shl_code]

根据表名、列簇名、start rowkey、版本数、记录数,获取数据的后台代码如下:

[mw_shl_code=java,true]public List<HBaseTableData> getTableData(String tableName, String cfs,
                        String startRowKey, int limit, int versions) throws IOException {
                List<HBaseTableData> datas = new ArrayList<>();
                Table table = HadoopUtils.getHBaseConnection().getTable(
                                getTableName(tableName));
                Scan scan = new Scan();
                scan.setMaxVersions(versions);
                if (startRowKey != "-1") {
                        scan.setStartRow(startRowKey.getBytes());
                }
                String[] cfsArr = cfs.split(Utils.COMMA, -1);
                for (String cf : cfsArr) {
                        scan.addFamily(cf.getBytes());
                }

                ResultScanner scanner = table.getScanner(scan);

                Result[] rows = scanner.next(limit);

                for (Result row : rows) {
                        // Cell[] cells = row.rawCells();

                        datas.addAll(getFromCells(row.rawCells()));
                }

                scanner.close();
                table.close();
                return datas;
        }[/mw_shl_code]

通过设置Scan的maxVersions以及startRow 来限定版本数和开始遍历位置,通过设置scanner.next来限定获取的记录数;

3.对表进行增删改查:

3.1 新增
数据新增,通过指定表名、列簇名即可,如果列簇名指定多个,会提示错误:


2016-05-25_121451.png

数据新增使用window弹出框,为了把表名和列簇名传递到该window,使用了url加参数的方法(比较别扭的方式),具体如下:

[mw_shl_code=java,true]var win_table_add_data_ = $('#win_table_add_data').window({   
            width:450,   
            height:350,   
            modal:true,
            left:400,
            top:150,
            title:'数据新增',
            collapsible:false,
            minimizable:false,
            maximizable:false,
//            content: '<div style="padding:30px 20px 10px 20px;">' + "a" +'</div>'
            content: '<iframe id="tabIframe" src="hbaseCommand/data_add.jsp?tableName='+tableName_+'&cf='+cf_+
                    '" frameborder="0" style="border:0;width:100%;height:100%;">',
//            href:"hbaseCommand/data_add.jsp",
            onOpen:function(){   
                    // 修改对应的值;
//                    $('#data_add_ff_tableName').val(getFakeData('cc_data_retrieve_tableName'));
//                    $('#data_add_ff_family').val(cf_);  
//                    $('#data_add_ff_family').textbox('setValue',cf_);  
            
            }
        
        });[/mw_shl_code]

在弹出框中,用户可以输入rowkey,column,vlaue :

2016-05-25_121539.png

表名、列簇名不可编辑,用户点击添加后,直接put数据到表中;

[mw_shl_code=java,true]public boolean saveTableData(String tableName, String cfs, String rowkey,
                        String column, String value) throws IOException {
                Table table = HadoopUtils.getHBaseConnection().getTable(
                                getTableName(tableName));
                Put put = new Put(Bytes.toBytes(rowkey));
                put.addColumn(Bytes.toBytes(cfs), Bytes.toBytes(column),
                                Bytes.toBytes(value));

                table.put(put);
                table.close();
                return true;
        }[/mw_shl_code]

3.2数据删除
直接根据提供的数据使用checkAndDelete进行删除,防止在删除的时候数据被修改:


2016-05-25_121626.png

[mw_shl_code=java,true]public boolean deleteTableData(String tableName, String family,
                        String qualifier, String rowkey, String value, long timestamp)
                        throws IOException {
                Table table = HadoopUtils.getHBaseConnection().getTable(
                                getTableName(tableName));
                Delete delete = new Delete(Bytes.toBytes(rowkey));
                delete.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier),
                                timestamp);
                boolean flag = table.checkAndDelete(Bytes.toBytes(rowkey),
                                Bytes.toBytes(family), Bytes.toBytes(qualifier),
                                Bytes.toBytes(value), delete);

                table.close();

                return flag;
        }[/mw_shl_code]

3.3 数据更新
数据更新,同样需要选择一条记录,弹出框的方式类似数据新增(比较别扭的方式),不过可修改的内容只有值而已:


2016-05-25_121708.png

除了值之外,其他输入框都是只读的;后台实现,同样使用checkAndPut 方法:

[mw_shl_code=java,true]public boolean updateTableData(String tableName, String cfs, String rowkey,  
            String column, String value, long timestamp, String oldValue)  
            throws IOException {  
        Table table = HadoopUtils.getHBaseConnection().getTable(  
                getTableName(tableName));  
        Put put = new Put(Bytes.toBytes(rowkey));  
        put.addColumn(Bytes.toBytes(cfs), Bytes.toBytes(column), timestamp,  
                Bytes.toBytes(value));  
  
        table.checkAndPut(Bytes.toBytes(rowkey), Bytes.toBytes(cfs),  
                Bytes.toBytes(column), Bytes.toBytes(oldValue), put);  
        table.close();  
        return true;  
    }[/mw_shl_code]

2016-05-25_121801.png

4. 总结
1)HBase的相关API的使用不是很难,主要是如果是插入或者更新操作,需要保持记录前后一致,需要进行row lock,这时就需要用到checkAndXxx 操作了,具体可以参考:http://blog.csdn.net/fansy1990/article/details/51451583

2) 数据新增和数据更新弹出框的方式比较别扭,可以考虑使用新的方式(因为要进行参数的传递);


转自:fansy1990的专栏

已有(2)人评论

跳转到指定楼层
ml32 发表于 2016-5-26 10:20:31
HBase表管理系统
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条