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

pom.xml
這里要導(dǎo)入Hbase連接所需要包,需要找和你Hbase版本一致的包
<dependency> <groupId>org.apache.hbase</groupId> <artifactId>hbase-client</artifactId> <version>2.0.1</version> </dependency>
hbase-site.xml
我是用的配置文件連接方法,這個(gè)配置文件你在hbase的安裝目錄下的conf目錄就可以找到,然后你直接把它復(fù)制到項(xiàng)目的resources目錄下就好,當(dāng)然你也可以用application.properties配置文件外加注入和代碼的方式代替這個(gè)配置文件
HBaseConfig.java
這里因?yàn)橹恍柽B接Hbase就沒(méi)連接Hadoop,如果要連接Hadoop,Windows下還要下載winutils.exe工具,后面會(huì)介紹
@Configuration
public class HBaseConfig {
@Bean
public HBaseService getHbaseService() {
//設(shè)置臨時(shí)的hadoop環(huán)境變量,之后程序會(huì)去這個(gè)目錄下的\bin目錄下找winutils.exe工具,windows連接hadoop時(shí)會(huì)用到
//System.setProperty("hadoop.home.dir", "D:\\Program Files\\Hadoop");
//執(zhí)行此步時(shí),會(huì)去resources目錄下找相應(yīng)的配置文件,例如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);
}
/**
* 通過(guò)表名及過(guò)濾條件查詢數(shù)據(jù)
*/
private Map<String, Map<String, String>> queryData(String tableName, Scan scan) {
// <rowKey,對(duì)應(yīng)的行數(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;
// 行鍵,列族和列限定符一起確定一個(gè)單元(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 {
//設(shè)置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));
}
/**
* 關(guān)閉流
*/
private void close(Admin admin, ResultScanner rs, Table table) {
if (admin != null) {
try {
admin.close();
} catch (IOException e) {
log.error("關(guān)閉Admin失敗", e);
}
if (rs != null) {
rs.close();
}
if (table != null) {
rs.close();
}
if (table != null) {
try {
table.close();
} catch (IOException e) {
log.error("關(guān)閉Table失敗", e);
}
}
}
}
}
HBaseApplicationTests.java
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
class HBaseApplicationTests {
@Resource
private HBaseService hbaseService;
//測(cè)試創(chuàng)建表
@Test
public void testCreateTable() {
hbaseService.creatTable("test_base", Arrays.asList("a", "back"));
}
//測(cè)試加入數(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"});
}
//測(cè)試遍歷全表
@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);
});
}
}
運(yùn)行結(jié)果
Hbase數(shù)據(jù)庫(kù)查詢結(jié)果

IDEA的遍歷結(jié)果

報(bào)錯(cuò)與解決方案
報(bào)錯(cuò)一

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

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

解決方案:
這是因?yàn)樵赪indows下連接Hadoop需要一個(gè)叫Winutils.exe的工具,并且從源代碼可知,它會(huì)去讀你Windows下的環(huán)境變量,如果你不想在本地設(shè)置,可以用方法System.setProperty()設(shè)置實(shí)時(shí)環(huán)境變量,另外,如果你只用Hbase,其實(shí)這個(gè)報(bào)錯(cuò)并不影響你使用Hbase服務(wù)
代碼地址
https://github.com/xiaoxiamo/SpringBoot_HBase
到此這篇關(guān)于SpringBoot整合Hbase的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)SpringBoot整合Hbase內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
設(shè)計(jì)模式在Spring框架中的應(yīng)用匯總
這篇文章主要介紹了設(shè)計(jì)模式在Spring框架中的應(yīng)用匯總,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11
java中@Configuration使用場(chǎng)景
本文主要介紹了java中@Configuration使用場(chǎng)景,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
詳解如何在spring boot中使用spring security防止CSRF攻擊
這篇文章主要介紹了詳解如何在spring boot中使用spring security防止CSRF攻擊,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05
Java判斷一個(gè)實(shí)體是不是空的簡(jiǎn)單方法
這篇文章主要給大家介紹了關(guān)于Java判斷一個(gè)實(shí)體是不是空的簡(jiǎn)單方法,實(shí)際項(xiàng)目中我們會(huì)有很多地方需要判空校驗(yàn),文中給出了詳細(xì)的示例代碼,需要的朋友可以參考下2023-07-07
Java 5個(gè)人坐在一起(有關(guān)第五個(gè)人歲數(shù)的問(wèn)題)
利用遞歸的方法,遞歸分為回推和遞推兩個(gè)階段。要想知道第五個(gè)人歲數(shù),需知道第四人的歲數(shù),依次類推,推到第一人(10歲),再往回推,需要的朋友可以參考下2017-02-02
通過(guò)web控制當(dāng)前的SpringBoot程序重新啟動(dòng)
本文主要給大家介紹了如何通過(guò)web控制當(dāng)前的SpringBoot程序重新啟動(dòng),文章給出了詳細(xì)的代碼示例供大家參考,對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2023-11-11
Springboot+WebSocket實(shí)現(xiàn)一對(duì)一聊天和公告的示例代碼
這篇文章主要介紹了Springboot+WebSocket實(shí)現(xiàn)一對(duì)一聊天和公告的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04

