SpringBoot整合Hbase的實現(xiàn)示例
簡介
當單表數(shù)據(jù)量過大的時候,關系性數(shù)據(jù)庫會出現(xiàn)性能瓶頸,這時候我們就可以用NoSql,比如Hbase就是一個不錯的解決方案。接下來是用Spring整合Hbase的實際案例,且在最后會給出整合中可能會出現(xiàn)的問題,以及解決方案。這里我是用本地Windows的IDEA,與局域網(wǎng)的偽分布Hbase集群做的連接,其中Hbase集群包括的組件有:Jdk1.8、Hadoop2.7.6、ZooKeeper3.4.10、Hbase2.0.1,因為這里只是開發(fā)環(huán)境,所以做一個偽分布的就好,之后部署的時候再按生產(chǎn)環(huán)境要求來即可
整合步驟
目錄結構

pom.xml
這里要導入Hbase連接所需要包,需要找和你Hbase版本一致的包
<dependency> <groupId>org.apache.hbase</groupId> <artifactId>hbase-client</artifactId> <version>2.0.1</version> </dependency>
hbase-site.xml
我是用的配置文件連接方法,這個配置文件你在hbase的安裝目錄下的conf目錄就可以找到,然后你直接把它復制到項目的resources目錄下就好,當然你也可以用application.properties配置文件外加注入和代碼的方式代替這個配置文件
HBaseConfig.java
這里因為只需連接Hbase就沒連接Hadoop,如果要連接Hadoop,Windows下還要下載winutils.exe工具,后面會介紹
@Configuration
public class HBaseConfig {
@Bean
public HBaseService getHbaseService() {
//設置臨時的hadoop環(huán)境變量,之后程序會去這個目錄下的\bin目錄下找winutils.exe工具,windows連接hadoop時會用到
//System.setProperty("hadoop.home.dir", "D:\\Program Files\\Hadoop");
//執(zhí)行此步時,會去resources目錄下找相應的配置文件,例如hbase-site.xml
org.apache.hadoop.conf.Configuration conf = HBaseConfiguration.create();
return new HBaseService(conf);
}
}
HBaseService.java
這是做連接后的一些操作可以參考之后自己寫一下
public class HBaseService {
private Logger log = LoggerFactory.getLogger(HBaseService.class);
/**
* 管理員可以做表以及數(shù)據(jù)的增刪改查功能
*/
private Admin admin = null;
private Connection connection = null;
public HBaseService(Configuration conf) {
try {
connection = ConnectionFactory.createConnection(conf);
admin = connection.getAdmin();
} catch (IOException e) {
log.error("獲取HBase連接失敗!");
}
}
/**
* 創(chuàng)建表 create <table>, {NAME => <column family>, VERSIONS => <VERSIONS>}
*/
public boolean creatTable(String tableName, List<String> columnFamily) {
try {
//列族column family
List<ColumnFamilyDescriptor> cfDesc = new ArrayList<>(columnFamily.size());
columnFamily.forEach(cf -> {
cfDesc.add(ColumnFamilyDescriptorBuilder.newBuilder(
Bytes.toBytes(cf)).build());
});
//表 table
TableDescriptor tableDesc = TableDescriptorBuilder
.newBuilder(TableName.valueOf(tableName))
.setColumnFamilies(cfDesc).build();
if (admin.tableExists(TableName.valueOf(tableName))) {
log.debug("table Exists!");
} else {
admin.createTable(tableDesc);
log.debug("create table Success!");
}
} catch (IOException e) {
log.error(MessageFormat.format("創(chuàng)建表{0}失敗", tableName), e);
return false;
} finally {
close(admin, null, null);
}
return true;
}
/**
* 查詢所有表的表名
*/
public List<String> getAllTableNames() {
List<String> result = new ArrayList<>();
try {
TableName[] tableNames = admin.listTableNames();
for (TableName tableName : tableNames) {
result.add(tableName.getNameAsString());
}
} catch (IOException e) {
log.error("獲取所有表的表名失敗", e);
} finally {
close(admin, null, null);
}
return result;
}
/**
* 遍歷查詢指定表中的所有數(shù)據(jù)
*/
public Map<String, Map<String, String>> getResultScanner(String tableName) {
Scan scan = new Scan();
return this.queryData(tableName, scan);
}
/**
* 通過表名及過濾條件查詢數(shù)據(jù)
*/
private Map<String, Map<String, String>> queryData(String tableName, Scan scan) {
// <rowKey,對應的行數(shù)據(jù)>
Map<String, Map<String, String>> result = new HashMap<>();
ResultScanner rs = null;
//獲取表
Table table = null;
try {
table = getTable(tableName);
rs = table.getScanner(scan);
for (Result r : rs) {
// 每一行數(shù)據(jù)
Map<String, String> columnMap = new HashMap<>();
String rowKey = null;
// 行鍵,列族和列限定符一起確定一個單元(Cell)
for (Cell cell : r.listCells()) {
if (rowKey == null) {
rowKey = Bytes.toString(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
}
columnMap.put(
//列限定符
Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()),
//列族
Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()));
}
if (rowKey != null) {
result.put(rowKey, columnMap);
}
}
} catch (IOException e) {
log.error(MessageFormat.format("遍歷查詢指定表中的所有數(shù)據(jù)失敗,tableName:{0}", tableName), e);
} finally {
close(null, rs, table);
}
return result;
}
/**
* 為表添加或者更新數(shù)據(jù)
*/
public void putData(String tableName, String rowKey, String familyName, String[] columns, String[] values) {
Table table = null;
try {
table = getTable(tableName);
putData(table, rowKey, tableName, familyName, columns, values);
} catch (Exception e) {
log.error(MessageFormat.format("為表添加 or 更新數(shù)據(jù)失敗,tableName:{0},rowKey:{1},familyName:{2}", tableName, rowKey, familyName), e);
} finally {
close(null, null, table);
}
}
private void putData(Table table, String rowKey, String tableName, String familyName, String[] columns, String[] values) {
try {
//設置rowkey
Put put = new Put(Bytes.toBytes(rowKey));
if (columns != null && values != null && columns.length == values.length) {
for (int i = 0; i < columns.length; i++) {
if (columns[i] != null && values[i] != null) {
put.addColumn(Bytes.toBytes(familyName), Bytes.toBytes(columns[i]), Bytes.toBytes(values[i]));
} else {
throw new NullPointerException(MessageFormat.format(
"列名和列數(shù)據(jù)都不能為空,column:{0},value:{1}", columns[i], values[i]));
}
}
}
table.put(put);
log.debug("putData add or update data Success,rowKey:" + rowKey);
table.close();
} catch (Exception e) {
log.error(MessageFormat.format(
"為表添加 or 更新數(shù)據(jù)失敗,tableName:{0},rowKey:{1},familyName:{2}",
tableName, rowKey, familyName), e);
}
}
/**
* 根據(jù)表名獲取table
*/
private Table getTable(String tableName) throws IOException {
return connection.getTable(TableName.valueOf(tableName));
}
/**
* 關閉流
*/
private void close(Admin admin, ResultScanner rs, Table table) {
if (admin != null) {
try {
admin.close();
} catch (IOException e) {
log.error("關閉Admin失敗", e);
}
if (rs != null) {
rs.close();
}
if (table != null) {
rs.close();
}
if (table != null) {
try {
table.close();
} catch (IOException e) {
log.error("關閉Table失敗", e);
}
}
}
}
}
HBaseApplicationTests.java
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
class HBaseApplicationTests {
@Resource
private HBaseService hbaseService;
//測試創(chuàng)建表
@Test
public void testCreateTable() {
hbaseService.creatTable("test_base", Arrays.asList("a", "back"));
}
//測試加入數(shù)據(jù)
@Test
public void testPutData() {
hbaseService.putData("test_base", "000001", "a", new String[]{
"project_id", "varName", "coefs", "pvalues", "tvalues",
"create_time"}, new String[]{"40866", "mob_3", "0.9416",
"0.0000", "12.2293", "null"});
hbaseService.putData("test_base", "000002", "a", new String[]{
"project_id", "varName", "coefs", "pvalues", "tvalues",
"create_time"}, new String[]{"40866", "idno_prov", "0.9317",
"0.0000", "9.8679", "null"});
hbaseService.putData("test_base", "000003", "a", new String[]{
"project_id", "varName", "coefs", "pvalues", "tvalues",
"create_time"}, new String[]{"40866", "education", "0.8984",
"0.0000", "25.5649", "null"});
}
//測試遍歷全表
@Test
public void testGetResultScanner() {
Map<String, Map<String, String>> result2 = hbaseService.getResultScanner("test_base");
System.out.println("-----遍歷查詢?nèi)韮?nèi)容-----");
result2.forEach((k, value) -> {
System.out.println(k + "--->" + value);
});
}
}
運行結果
Hbase數(shù)據(jù)庫查詢結果

IDEA的遍歷結果

報錯與解決方案
報錯一

解決方案:
這是參數(shù)配置的有問題,如果你是用hbase-site.xml配置文件配置的參數(shù),那么檢查它,用代碼配置就檢查代碼參數(shù)
報錯二

解決方案:
更改windows本地hosts文件,C:\Windows\System32\drivers\etc\hosts,添加Hbase服務所在主機地址與主機名稱,這里你如果保存不了hosts文件,把它拉出到桌面改好再拉回即可
報錯三

解決方案:
這是因為在Windows下連接Hadoop需要一個叫Winutils.exe的工具,并且從源代碼可知,它會去讀你Windows下的環(huán)境變量,如果你不想在本地設置,可以用方法System.setProperty()設置實時環(huán)境變量,另外,如果你只用Hbase,其實這個報錯并不影響你使用Hbase服務
代碼地址
https://github.com/xiaoxiamo/SpringBoot_HBase
到此這篇關于SpringBoot整合Hbase的實現(xiàn)示例的文章就介紹到這了,更多相關SpringBoot整合Hbase內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
LambdaQueryWrapper與QueryWrapper的使用方式
這篇文章主要介紹了LambdaQueryWrapper與QueryWrapper的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05
spring boot實現(xiàn)自動輸出word文檔功能的實例代碼
這篇文章主要介紹了spring boot實現(xiàn)自動輸出word文檔功能的實例代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-04-04
Java Socket實現(xiàn)多人聊天系統(tǒng)
這篇文章主要為大家詳細介紹了Java Socket實現(xiàn)多人聊天系統(tǒng),具有圖形界面,實現(xiàn)文件傳輸功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-07-07

