├── README.md ├── pom.xml └── src ├── main └── java │ └── com │ └── yaoqi │ └── hbase │ └── component │ ├── HBaseApp.java │ ├── assertion │ └── Assert.java │ ├── config │ └── HBaseConfig.java │ ├── constant │ ├── CommonConstant.java │ ├── ExceptionMessage.java │ └── KerberosConstant.java │ ├── operations │ └── HBaseOperations.java │ └── template │ └── HBaseTemplate.java └── test ├── java └── com │ └── yaoqi │ └── hbase │ └── component │ ├── assertion │ └── AssertTest.java │ └── template │ └── HBaseTemplateTest.java └── resources └── application.yml /README.md: -------------------------------------------------------------------------------- 1 | # HBase 组件接口文档 2 | 3 | ---- 4 | 5 | #### 使用说明 6 | 7 | 基本概念 8 | 9 | table: 表 10 | 11 | columnFamily:列族,一个表下可以有多个列族,但是不建议设置多个列族,HBase建议设计长窄型的表而不是短宽型。 12 | 13 | qualifier:列,一个列族下可以有多列,一个表中的列可以是不对齐的,但是这样效率不高,同一张表中的列最好是相同的。 14 | 15 | cell:一列数据下的一个单元格,一个列下可以有多个单元格,根据版本号区分,默认每次读取最新版本的数据,cell下的存储是数据本身。 16 | 17 | row: 行,多列数据组成一行,一行中有多个qualifier。 18 | 19 | rowKey: 行健,用于唯一标识一行数据,一行下有多列,行健的设计直接关系到查询的效率。 20 | 21 | ### HBase配置 22 | 23 | 以下配置为最基础配置,缺一不可。 24 | 25 | ``` yml 26 | HBase: 27 | conf: 28 | quorum: 192.168.80.234:2181,192.168.80.235:2181,192.168.80.241:2181 29 | znodeParent: /hbase-unsecure 30 | #如果有更多配置,写在config下,例如: 31 | #config: 32 | # key: value 33 | # key: value 34 | ``` 35 | 36 | 如果需要更多配置,需要在config中配置,以key-value的形式书写。 37 | 38 | 39 | ### 参数说明 40 | 41 | quorum是HBase中zookeeper的配置,znodeParent是HBase配置在zookeeper中的路径。 42 | 43 | 带kerberos认证的配置如下: 44 | 45 | ``` yml 46 | # HBase配置 47 | HBase: 48 | conf: 49 | quorum: 192.168.80.54:2181,192.168.80.62:2181,192.168.80.64:2181,192.168.80.78:2181,192.168.80.52:2181 50 | znodeParent: /hbase-secure 51 | config: 52 | #keytab地址路径 53 | user-keytab: D:\semptian\environment\security/hbase.service.keytab 54 | #如果使用kb认证请写kerberos否则不用写 55 | authMethod: kerberos 56 | #master.kerberos.principal 57 | masterPrincipal: hbase/node248@SEMPTIAN.COM 58 | #regionserver.kerberos.principal regionserverPrincipal/hbaseSitePath 二选一,一些环境下使用hbaseSitePath更简单 59 | #regionserverPrincipal: root/_HOST@SEMPTIAN.COM 60 | #hbseSite配置文件路径D:\kerberos\hbase-kb\hbase-site.xml 61 | hbaseSitePath: D:\semptian\environment\security/hbase-site.xml 62 | #coreSitePath: D:\kerberos\dev-hbase-kb\core-site.xml 63 | # 刷新认证周期,单位:小时 64 | refreshAuth: 8 65 | ``` 66 | 67 | ### 认证配置参数说明 68 | 69 | user-keytab 和 masterPrincipal 是对应的,一个对应用户的认证文件,一个对应用户。 70 | hbaseSitePath 是hbase-site.xml的文件路径。 71 | 72 | 在jdk中会自动设置认证过期时间为24小时,所以在组件中需要对认证进行刷新,重新建立连接。refreshAuth 就是配置刷新认证的周期,一般小于24小时, 73 | 建议12小时,因为重新建立连接需要消耗一些资源。 74 | 75 | ## 简单示例 76 | 77 | 引入组件jar包: 78 | 79 | ``` xml 80 | 81 | com.semptian.hbase.component 82 | hbase-component 83 | 1.0.1-SNAPSHOT 84 | 85 | ``` 86 | 87 | 在需要的地方注入HBaseOperations接口,该接口的实现类是HBaseTemplate,通过这个类来操作HBase。 88 | 89 | ``` java 90 | @Autowired 91 | private HBaseOperations hBaseDao; 92 | ``` 93 | 94 | 查询一条数据,通过rowKey查询: 95 | 96 | ``` java 97 | public void testQueryTable() { 98 | Result result = hBaseDao.queryByTableNameAndRowKey( 99 | "LBS", 9223372036854775803L); 100 | System.out.println(result.isEmpty()); 101 | result.listCells().forEach(cell -> { 102 | System.out.println( 103 | "row:" + Bytes.toLong(CellUtil.cloneRow(cell)) + 104 | ",family:"+ Bytes.toString(CellUtil.cloneFamily(cell)) + 105 | ", qualifier: " + Bytes.toString(CellUtil.cloneQualifier(cell)) + 106 | ", value:" + Bytes.toString(CellUtil.cloneValue(cell))); 107 | }); 108 | } 109 | 110 | ``` 111 | 112 | ## 表的基本操作 113 | 114 | ### 新建表 115 | 116 | 创建表通过HBaseTemplate就可以实现,HBaseTemplate类中带有这个方法。 117 | 118 | 操作示例: 119 | ``` java 120 | hBaseDao.createTable("HBASE-COMPONENT_1", "CF1", "CF2"); 121 | ``` 122 | 上述代码创建了一张表,HBASE-COMPONENT_1 是表名,CF1,CF2代表这个表有两个列族。 123 | 124 | 如果有多个列族可以往后面加,列族不建议设置很多个。 125 | 126 | ### 删除表 127 | 128 | ``` java 129 | hBaseDao.dropTable("HBASE-COMPONENT_1"); 130 | ``` 131 | 参数是表名,通过表名删除表。 132 | 133 | ### 判断表是否存在 134 | 135 | ``` java 136 | hBaseDao.tableExists("lbs"); 137 | ``` 138 | 这里的表名是区分大小写的。返回值:boolean。 139 | 140 | ### 新增数据 141 | 142 | #### 新增一条数据 143 | 144 | 需要注意的是在HBase中的存储的数据是不分格式的,都是以字节数组的形式存储,因此在存储一条数据时需要将数据都转化成字节数组。 145 | 146 | String格式的数据能直接转换为字节数组getBytes(),但是其他格式的数据需要借助工具作转换。 147 | 148 | 这里需要格外注意rowKey的格式,用什么格式存就决定了用什么格式取。 149 | ``` java 150 | hBaseDao.put("HBase-component", "1534154424340", "CF1", "test_1", Bytes.toBytes("testData")); 151 | ``` 152 | 153 | 参数说明: 154 | ``` java 155 | (1) tableName 目标数据表 156 | (2) rowName rowKey 157 | (3) familyName 列族名 158 | (4) qualifier 列名 159 | (5) data 字节数组类型的数据 160 | 161 | ``` 162 | 这里新增一条数据是填充数据到一个cell中去。 163 | 164 | #### 批量新增数据 165 | 166 | ``` java 167 | String rowKey = String.valueOf(System.currentTimeMillis()); 168 | Put put = new Put(rowKey.getBytes()); 169 | String defaultColumn = "CF1"; 170 | String column1 = "col1"; 171 | String column2 = "col2"; 172 | String column3 = "col3"; 173 | 174 | String value = "test"; 175 | put.addColumn(defaultColumn.getBytes(), column1.getBytes(), value.getBytes()); 176 | put.addColumn(defaultColumn.getBytes(), column2.getBytes(), value.getBytes()); 177 | put.addColumn(defaultColumn.getBytes(), column3.getBytes(), value.getBytes()); 178 | 179 | List putList = new ArrayList<>(); 180 | putList.add(put); 181 | putList.add(put); 182 | putList.add(put); 183 | putList.add(put); 184 | putList.add(put); 185 | 186 | hBaseDao.putBatch("HBase-component", putList); 187 | ``` 188 | 批量插入数据就是使用多个Put对象,putBatch(...)方法的参数:表名,putList(多个put的集合)。 189 | 注意批量插入数据也都是插入字节数组格式的数据。 190 | 191 | ### 删除数据 192 | 193 | #### 删除一条数据 194 | 195 | ``` java 196 | hBaseDao.delete("HBase-component", "1534210201115", "CF1", "col2"); 197 | ``` 198 | 参数说明: 199 | 200 | (1) 表名 201 | 202 | (2) rowKey 203 | 204 | (3) 列族名 205 | 206 | (4) 列名 207 | 208 | 这里删除是删除一个cell下的数据 209 | 210 | #### 批量删除数据 211 | 212 | ``` java 213 | String tableName = "HBase-component"; 214 | String rowKey1 = "1534164113922"; 215 | String rowKey2 = "1534168248328"; 216 | 217 | List deleteList = new ArrayList<>(); 218 | Delete delete = new Delete(rowKey1.getBytes()); 219 | Delete delete1 = new Delete(rowKey2.getBytes()); 220 | deleteList.add(delete); 221 | deleteList.add(delete1); 222 | hBaseDao.deleteBatch(tableName, deleteList); 223 | ``` 224 | 批量删除需要借助Delete对象。 225 | 226 | ### 查询 227 | 228 | ### 单条结果查询 229 | ``` java 230 | Result result = hBaseDao.queryByTableNameAndRowKey("LBS", 9223372036854775803L); 231 | System.out.println(result.isEmpty()); 232 | result.listCells().forEach(cell -> { 233 | System.out.println( 234 | " row:" + Bytes.toLong(CellUtil.cloneRow(cell)) + 235 | " family:"+ Bytes.toString(CellUtil.cloneFamily(cell)) + 236 | " qualifier: " + Bytes.toString(CellUtil.cloneQualifier(cell)) + 237 | " value:" + Bytes.toString(CellUtil.cloneValue(cell))); 238 | }); 239 | ``` 240 | queryByTableNameAndRowKey()该方法是通过表名和rowKey查询数据,这里的rowKey支持多种类型,Long,double,Integer几种类型。 241 | 至于这里传什么类型的参数,取决于插入数据时rowKey的类型,虽然HBase里存储的都是字节数组,但是对类型是敏感的,如果类型对不上可能会出错。 242 | 243 | ### 批量扫描 244 | 245 | ``` java 246 | // 构建scan 247 | Scan scan = new Scan(); 248 | 249 | // 设置时间戳,计算时间差 250 | Long timeDifference = 2L * 30L * 24L * 60L * 60L * 1000L; 251 | Long endTime = System.currentTimeMillis(); 252 | Long fromTime = endTime - timeDifference; 253 | 254 | // 设置时间过滤器 255 | FilterList filterList = new FilterList(); 256 | Filter startTimeFilter = new SingleColumnValueFilter( 257 | DEFAULT_COLUMN_FAMILY.getBytes(), 258 | DATA_CREATE_TIME.getBytes(), 259 | CompareFilter.CompareOp.GREATER, 260 | Bytes.toBytes(fromTime) 261 | ); 262 | 263 | Filter endTimeFilter = new SingleColumnValueFilter( 264 | DEFAULT_COLUMN_FAMILY.getBytes(), 265 | DATA_CREATE_TIME.getBytes(), 266 | CompareFilter.CompareOp.LESS, 267 | Bytes.toBytes(endTime) 268 | ); 269 | 270 | 271 | filterList.addFilter(startTimeFilter); 272 | filterList.addFilter(endTimeFilter); 273 | 274 | scan.setFilter(filterList); 275 | 276 | // 获取结果集 277 | ResultScanner resultScanner = hBaseTemplate.queryByScan(TABLE_NAME, scan); 278 | 279 | // 遍历结果集 280 | try{ 281 | if (resultScanner != null) { 282 | resultScanner.forEach(result -> { 283 | List cellList = result.listCells(); 284 | ... 285 | } 286 | } 287 | }finally{ 288 | if (resultScanner != null) { 289 | resultScanner.close(); 290 | } 291 | } 292 | 293 | ``` 294 | 295 | 批量查询可以通过queryByScan()方法实现,第一个参数是表名,第二个参数是scan,通过构建不同的scan来查询,过滤器也是在构建scan对象是添加的,可以添加多个过滤器。 296 | 297 | *需要注意的是这里的ResultScanner类,在遍历结果集时需要使用try-finally结构,在使用完resultScanner对象之后关闭该对象。HBase官方文档上强调了这一点。因此在使用ResultScanner对象时需要格外注意。* 298 | 299 | 常见过滤器: 300 | 301 | 行健过滤器:RowFilter 302 | 303 | 列族过滤器:FamilyFilter 304 | 305 | 值过滤器:ValueFilter 306 | 307 | 列过滤器:QualifierFilter 308 | 309 | 单列值过滤器:SingleColumnValueFilter(会返回满足条件的行) 310 | 311 | 单列值排除过滤器:SingleColumnExcludeFilter(返回排除了该列的结果,与单列值过滤器相反) 312 | 313 | 前缀过滤器:PrefixFilter(这个过滤器是针对行健的,在构造方法中传入字节数组形式的内容,过滤器会去匹配行健) 314 | 315 | 页数过滤器:PageFilter(使用pageFilter过滤器的时候需要注意,并不是设置了页数大小就能返回相应数目的结果) 316 | 317 | ``` java 318 | String tableName = "RECOMMEND_ENGINE_DATA_MODEL"; 319 | Scan scan = new Scan(); 320 | 321 | PageFilter pageFilter = new PageFilter(1); 322 | scan.setFilter(pageFilter); 323 | 324 | ResultScanner resultScanner = hBaseDao.queryByScan(tableName, scan); 325 | 326 | try{ 327 | resultScanner.forEach(result -> { 328 | result.listCells().forEach(cell -> { 329 | // process 330 | }); 331 | }finally{ 332 | if (resultScanner != null) { 333 | resultScanner.close(); 334 | } 335 | } 336 | ``` 337 | 338 | 上面这段代码中设置了页面大小为1,预期是返回一条数据,但是结果会返回两条数据,这时返回的结果数会取决于regionServer的数量。 339 | 340 | 如果是FilterList,FilterList的顺序会影响PageFilter的效果。 341 | 342 | 一般比较型过滤器,需要用CompareFilter.CompareOp中的比较运算符。所有的过滤器都是用Scan对象去设置。 343 | 344 | #### 多过滤器查询 345 | ``` java 346 | String tableName = "HBase-component"; 347 | Scan scan = new Scan(); 348 | PageFilter pageFilter = new PageFilter(1); 349 | 350 | SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter( 351 | "CF1".getBytes(), 352 | "col1".getBytes(), 353 | CompareFilter.CompareOp.EQUAL, 354 | new SubstringComparator("group")); 355 | 356 | singleColumnValueFilter.setFilterIfMissing(true); 357 | FilterList filterList = new FilterList(); 358 | filterList.addFilter(singleColumnValueFilter); 359 | filterList.addFilter(pageFilter); 360 | 361 | scan.setFilter(filterList); 362 | ResultScanner resultScanner = hBaseDao.queryByScan(tableName, scan); 363 | 364 | try { 365 | resultScanner.forEach(result -> { 366 | result.listCells().forEach(cell -> { 367 | System.out.println( 368 | " row:" + Bytes.toString(CellUtil.cloneRow(cell)) + 369 | " family:"+ Bytes.toString(CellUtil.cloneFamily(cell)) + 370 | " qualifier: " + Bytes.toString(CellUtil.cloneQualifier(cell))+ 371 | " value:" + Bytes.toString(CellUtil.cloneValue(cell))); 372 | }); 373 | }); 374 | } finally { 375 | if (resultScanner != null) { 376 | resultScanner.close(); 377 | } 378 | } 379 | ``` 380 | 381 | 多过滤器需要用到FilterList,也是直接设置到Scan对象中。多过滤器的时候需要注意过滤器的顺序问题,例如上面代码中如果将两个过滤器调换顺序,查询的结果也是不一样的。 382 | 383 | ### 结果集的映射 384 | 385 | 在HBase中,默认所有的顺序都是按照字母序排列,例如CF1列族下有多个列:col1、col2、col3,那么在遍历结果集时,listCells()中的cell的顺序总是按照列名的字母序来排列的。 386 | 387 | 所以cellList.get(0)就是对应col1中的数据,cellList.get(1)就是对应col2中的数据,cellList.get(2)就是对应col3中的数据。 388 | 389 | 如果列名为a、b、c那分别对应的下标为cellList.get(0)、cellList.get(1)、cellList.get(2) -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | com.yaoqi.hbase.component 7 | hbase-component 8 | 1.0.2-SNAPSHOT 9 | jar 10 | 11 | org.springframework.boot 12 | spring-boot-starter-parent 13 | 1.5.10.RELEASE 14 | 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-starter 19 | 20 | 21 | org.apache.hbase 22 | hbase-shaded-client 23 | 2.0.2 24 | 25 | 26 | org.apache.hadoop 27 | hadoop-common 28 | 2.6.4 29 | jar 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-test 35 | test 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-maven-plugin 45 | 46 | true 47 | true 48 | 49 | 50 | 51 | org.apache.maven.plugins 52 | maven-compiler-plugin 53 | 54 | 1.8 55 | 1.8 56 | UTF-8 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/main/java/com/yaoqi/hbase/component/HBaseApp.java: -------------------------------------------------------------------------------- 1 | package com.yaoqi.hbase.component; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @Author YaoQi 8 | * Date 2018/8/13 11:35 9 | * Modified 10 | * Description 11 | */ 12 | @SpringBootApplication 13 | public class HBaseApp { 14 | public static void main(String[] args) { 15 | SpringApplication.run(HBaseApp.class); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/yaoqi/hbase/component/assertion/Assert.java: -------------------------------------------------------------------------------- 1 | package com.yaoqi.hbase.component.assertion; 2 | 3 | import com.yaoqi.hbase.component.constant.ExceptionMessage; 4 | import org.springframework.util.StringUtils; 5 | 6 | /** 7 | * @author YaoQi 8 | * Date 2018/8/13 17:00 9 | * Modified 10 | * Description 参数断言 11 | */ 12 | public class Assert { 13 | 14 | 15 | /** 16 | * String 类型参数校验,参数不合法直接抛出异常 17 | * 18 | * @param text 参数 19 | */ 20 | public static void hasLength(String text) { 21 | if (!StringUtils.hasLength(text)) { 22 | throw new IllegalArgumentException(ExceptionMessage.HAS_LENGTH_MSG); 23 | } 24 | } 25 | 26 | /** 27 | * 参数批量判断是否为空 28 | * 29 | * @param text 可传多个参数 30 | */ 31 | public static void hasLengthBatch(String... text) { 32 | for (int i = 0; i < text.length; i++) { 33 | hasLength(text[i]); 34 | } 35 | } 36 | 37 | /** 38 | * Object类型参数校验,参数不合法直接抛出异常 39 | * 40 | * @param object 对象类型参数 41 | */ 42 | public static void notNull(Object object) { 43 | if (object == null) { 44 | throw new IllegalArgumentException(ExceptionMessage.NOT_NULL_MSG); 45 | } 46 | } 47 | 48 | /** 49 | * 参数批量判断 50 | * 51 | * @param objects 多个参数集合 52 | */ 53 | public static void notNullBatch(Object... objects) { 54 | for (Object object : objects) { 55 | notNull(object); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/yaoqi/hbase/component/config/HBaseConfig.java: -------------------------------------------------------------------------------- 1 | package com.yaoqi.hbase.component.config; 2 | 3 | import com.yaoqi.hbase.component.constant.KerberosConstant; 4 | import org.apache.commons.lang.StringUtils; 5 | import org.apache.hadoop.conf.Configuration; 6 | import org.apache.hadoop.fs.Path; 7 | import org.apache.hadoop.hbase.HBaseConfiguration; 8 | import org.apache.hadoop.hbase.client.Connection; 9 | import org.apache.hadoop.hbase.client.ConnectionFactory; 10 | import org.apache.hadoop.hbase.security.User; 11 | import org.apache.hadoop.hbase.shaded.org.apache.commons.lang3.concurrent.BasicThreadFactory; 12 | import org.apache.hadoop.security.UserGroupInformation; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | import org.springframework.boot.context.properties.ConfigurationProperties; 16 | import org.springframework.context.annotation.ComponentScan; 17 | 18 | import javax.annotation.PostConstruct; 19 | import java.io.IOException; 20 | import java.util.Map; 21 | import java.util.concurrent.ConcurrentLinkedQueue; 22 | import java.util.concurrent.ScheduledExecutorService; 23 | import java.util.concurrent.ScheduledThreadPoolExecutor; 24 | import java.util.concurrent.TimeUnit; 25 | 26 | /** 27 | * @author YaoQi 28 | * Date 2018/8/13 11:32 29 | * Modified 30 | * Description HBase配置类 31 | */ 32 | @org.springframework.context.annotation.Configuration 33 | @ConfigurationProperties(prefix = "HBase.conf") 34 | @ComponentScan(value = "com.semptian.base.hbasecomponent") 35 | public class HBaseConfig { 36 | 37 | private static final Logger logger = LoggerFactory.getLogger(HBaseConfig.class); 38 | 39 | private String quorum; 40 | private String znodeParent; 41 | private Map config; 42 | private User user = null; 43 | private volatile Connection connection; 44 | private static ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue<>(); 45 | 46 | /** 47 | * 初始化配置 48 | * 49 | * @return 50 | * @throws IOException 51 | */ 52 | private Configuration configuration() throws IOException { 53 | Configuration configuration = HBaseConfiguration.create(); 54 | logger.info("zookeeper node : {}", quorum); 55 | logger.info("znodeParent is : {}", znodeParent); 56 | configuration.set("hbase.zookeeper.quorum", quorum); 57 | configuration.set("zookeeper.znode.parent", znodeParent); 58 | if (config != null && config.containsKey(KerberosConstant.AUTH_METHOD) && KerberosConstant.KERBEROS.equals(config.get(KerberosConstant.AUTH_METHOD))) { 59 | String keytabPath = config.get("user-keytab"); 60 | String masterPrincipal = config.get("masterPrincipal"); 61 | String regionserverPrincipal = config.get("regionserverPrincipal"); 62 | String hbaseSitePath = config.get("hbaseSitePath"); 63 | String coreSitePath = config.get("coreSitePath"); 64 | configuration.set("hadoop.security.authentication", "kerberos"); 65 | configuration.set("hbase.security.authentication", "kerberos"); 66 | if (StringUtils.isNotBlank(hbaseSitePath)) { 67 | configuration.addResource(new Path(hbaseSitePath)); 68 | } 69 | if (StringUtils.isNotBlank(coreSitePath)) { 70 | configuration.addResource(new Path(coreSitePath)); 71 | } 72 | if (StringUtils.isNotBlank(masterPrincipal) && StringUtils.isNotBlank(regionserverPrincipal)) { 73 | configuration.set("hbase.master.kerberos.principal", masterPrincipal); 74 | configuration.set("hbase.regionserver.kerberos.principal", regionserverPrincipal); 75 | } 76 | UserGroupInformation.setConfiguration(configuration); 77 | UserGroupInformation.loginUserFromKeytab(masterPrincipal, keytabPath); 78 | UserGroupInformation loginUser = UserGroupInformation.getLoginUser(); 79 | user = User.create(loginUser); 80 | } 81 | // 将config中的配置加入到configuration中 82 | if (config != null && !config.isEmpty()) { 83 | config.forEach(configuration::set); 84 | } 85 | return configuration; 86 | } 87 | 88 | /** 89 | * 重新初始化连接,解决认证过期问题,默认过期时间为24h,因此reInitial() 的执行周期应该小于24h 90 | * 认证环境下才会开启 91 | */ 92 | @PostConstruct 93 | private void reInitial() { 94 | int refreshAuth = 12; 95 | boolean openReInitial = false; 96 | if (config != null && !config.isEmpty()) { 97 | String refreshAuthConfig = config.get(KerberosConstant.REFRESH_AUTH); 98 | if (StringUtils.isNotEmpty(refreshAuthConfig)) { 99 | // 如果有配置,则按照配置的时间进行刷新 100 | refreshAuth = Integer.valueOf(refreshAuthConfig); 101 | } 102 | String authMethod = config.get(KerberosConstant.AUTH_METHOD); 103 | if (KerberosConstant.KERBEROS.equals(authMethod)) { 104 | openReInitial = true; 105 | } 106 | } 107 | if (openReInitial) { 108 | // 认证环境下才会开启 109 | logger.info("create new thread refresh connection."); 110 | ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, 111 | new BasicThreadFactory.Builder().namingPattern("renew-connection-pool-%d").daemon(true).build()); 112 | final int finalRefreshAuth = refreshAuth; 113 | executorService.submit((Runnable) () -> { 114 | while (true) { 115 | try { 116 | TimeUnit.HOURS.sleep(finalRefreshAuth); 117 | } catch (InterruptedException e) { 118 | logger.error("reLogin kerberos error ,error info : {}", e.getMessage()); 119 | } 120 | initial(); 121 | closeOldConnection(); 122 | logger.info("renew connection:{}", connection); 123 | } 124 | }); 125 | } 126 | } 127 | 128 | /** 129 | * 获取连接 130 | * 131 | * @return 132 | */ 133 | public Connection getConnection() { 134 | if (connection == null) { 135 | connection = initial(); 136 | } 137 | return connection; 138 | } 139 | 140 | /** 141 | * 初始化连接,如果存在老的连接则加入队列 142 | * 143 | * @return 144 | */ 145 | @PostConstruct 146 | private Connection initial() { 147 | Connection newConnection; 148 | try { 149 | newConnection = ConnectionFactory.createConnection(configuration(), user); 150 | Connection oldConnection = connection; 151 | if (newConnection != null) { 152 | connection = newConnection; 153 | if (oldConnection != null) { 154 | queue.add(oldConnection); 155 | } 156 | } 157 | } catch (IOException e) { 158 | e.printStackTrace(); 159 | } 160 | return connection; 161 | } 162 | 163 | /** 164 | * 关闭老的连接 165 | */ 166 | private void closeOldConnection() { 167 | if (queue != null && !queue.isEmpty() && queue.size() > 1) { 168 | // 在创建connection的第二个周期开始清空队列 169 | Connection oldConnection = queue.poll(); 170 | if (oldConnection != null && !oldConnection.isClosed()) { 171 | try { 172 | oldConnection.close(); 173 | } catch (IOException e) { 174 | logger.error("oldConnection close failed."); 175 | e.printStackTrace(); 176 | } 177 | } 178 | } 179 | } 180 | 181 | public String getQuorum() { 182 | return quorum; 183 | } 184 | 185 | public void setQuorum(String quorum) { 186 | this.quorum = quorum; 187 | } 188 | 189 | public String getZnodeParent() { 190 | return znodeParent; 191 | } 192 | 193 | public void setZnodeParent(String znodeParent) { 194 | this.znodeParent = znodeParent; 195 | } 196 | 197 | public Map getConfig() { 198 | return config; 199 | } 200 | 201 | public void setConfig(Map config) { 202 | this.config = config; 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /src/main/java/com/yaoqi/hbase/component/constant/CommonConstant.java: -------------------------------------------------------------------------------- 1 | package com.yaoqi.hbase.component.constant; 2 | 3 | /** 4 | * @author : YaoQi 5 | * Date: 2018/10/27 17:57 6 | * Modified: 7 | * Description:公共常量类 8 | */ 9 | public class CommonConstant { 10 | 11 | /** 12 | * 批量插入最大长度限制 13 | */ 14 | public static final Integer BATCH_PUT_LIMIT = 2000000; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/yaoqi/hbase/component/constant/ExceptionMessage.java: -------------------------------------------------------------------------------- 1 | package com.yaoqi.hbase.component.constant; 2 | 3 | /** 4 | * @author YaoQi 5 | * Date 2018/8/13 16:52 6 | * Modified 7 | * Description 异常信息常量类 8 | */ 9 | public class ExceptionMessage { 10 | 11 | /** 12 | * 参数不为空异常信息 13 | */ 14 | public static final String NOT_NULL_MSG = "This argument is required. It must not be null!"; 15 | 16 | /** 17 | * String 参数长度异常信息 18 | */ 19 | public static final String HAS_LENGTH_MSG = "This String must have length. It must not be null or empty!"; 20 | 21 | /** 22 | * 表名不存在异常信息 23 | */ 24 | public static final String TABLE_NOT_EXISTS_MSG = "Table is not exists!"; 25 | 26 | /** 27 | * 表名已存在异常信息 28 | */ 29 | public static final String TABLE_ALREADY_EXISTS_MSG = "Table is already exists!"; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/yaoqi/hbase/component/constant/KerberosConstant.java: -------------------------------------------------------------------------------- 1 | package com.yaoqi.hbase.component.constant; 2 | 3 | /** 4 | * @author YaoQi 5 | * date 2019 / 12 / 17 / 16: 12 6 | * desc 7 | **/ 8 | public class KerberosConstant { 9 | 10 | /** 11 | * 认证方式 12 | */ 13 | public static final String AUTH_METHOD = "authMethod"; 14 | /** 15 | * kerberos 认证类型 16 | */ 17 | public static final String KERBEROS = "kerberos"; 18 | 19 | /** 20 | * 认证刷新配置 21 | */ 22 | public static final String REFRESH_AUTH = "refreshAuth"; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/yaoqi/hbase/component/operations/HBaseOperations.java: -------------------------------------------------------------------------------- 1 | package com.yaoqi.hbase.component.operations; 2 | 3 | import org.apache.hadoop.hbase.client.*; 4 | 5 | import java.io.IOException; 6 | import java.util.List; 7 | 8 | /** 9 | * @author YaoQi 10 | * Date 2018/8/13 14:46 11 | * Modified 12 | * Description 组件接口 13 | */ 14 | public interface HBaseOperations { 15 | 16 | /** 17 | * 创建一张表 18 | * 19 | * @param tableName 表名 20 | * @param familyName 列族名 21 | */ 22 | void createTable(final String tableName, final String... familyName); 23 | 24 | /** 25 | * 创建带有分区的表 26 | * 27 | * @param tableName 28 | * @param familyName 29 | * @param splitkeys 30 | */ 31 | void createTable(String tableName, List familyName, byte[][] splitkeys); 32 | 33 | /** 34 | * 通过表名和rowKey获取数据 35 | * 36 | * @param tableName 表名 37 | * @param rowKeyVar rowKey 泛型 可支持多种类型{String,Long,Double} 38 | * @return Result 类型 39 | */ 40 | Result queryByTableNameAndRowKey(String tableName, T rowKeyVar); 41 | 42 | /** 43 | * 自定义查询 44 | * 45 | * @param tableName 表名 46 | * @param getList 请求体 47 | * @return Result类型 48 | */ 49 | Result[] query(String tableName, List getList); 50 | 51 | /** 52 | * 判断表名是否存在 53 | * 54 | * @param tableName 表名 String ,注意这里区分大小写 55 | * @return 56 | */ 57 | boolean tableExists(String tableName); 58 | 59 | /** 60 | * 新增一条数据 61 | * 62 | * @param tableName 目标数据表 63 | * @param rowName rowKey 64 | * @param familyName 列族名 65 | * @param qualifier 列名 66 | * @param data 字节数组类型的数据 67 | */ 68 | void put(final String tableName, final String rowName, final String familyName, final String qualifier, final byte[] data); 69 | 70 | /** 71 | * 批量插入数据 72 | * 73 | * @param tableName 表名 74 | * @param putList put集合 75 | * @throws IOException 76 | */ 77 | void putBatch(final String tableName, List putList) throws IOException; 78 | 79 | /** 80 | * 删除一个列族下的数据 81 | * 82 | * @param tableName target table 83 | * @param rowName row name 84 | * @param familyName family 85 | */ 86 | void delete(final String tableName, final String rowName, final String familyName); 87 | 88 | /** 89 | * 删除某个列下的数据 90 | * 91 | * @param tableName 目标数据表 92 | * @param rowName rowKey 93 | * @param familyName 列族名 94 | * @param qualifier 列名 95 | */ 96 | void delete(final String tableName, final String rowName, final String familyName, final String qualifier); 97 | 98 | /** 99 | * 批量删除数据 100 | * 101 | * @param tableName 表名 102 | * @param deleteList 需要删除的数据 103 | */ 104 | void deleteBatch(final String tableName, List deleteList); 105 | 106 | /** 107 | * 通过scan查询数据 108 | * 109 | * @param tableName 表名 110 | * @param scan scan 111 | * @return 返回 ResultScanner 112 | */ 113 | ResultScanner queryByScan(final String tableName, Scan scan); 114 | 115 | /** 116 | * 删除表 117 | * 118 | * @param tableName 表名 119 | */ 120 | void dropTable(String tableName); 121 | 122 | /** 123 | * 批量删除表 124 | * 125 | * @param tableNames 126 | */ 127 | void dropTable(List tableNames); 128 | 129 | /** 130 | * 清空表数据 131 | * 132 | * @param tableName 133 | * @throws IOException 134 | */ 135 | void truncateTable(String tableName) throws IOException; 136 | 137 | /** 138 | * 删除指定行指定列 139 | * 140 | * @param tableName 141 | * @param family 142 | * @param rowKey 143 | * @param column 144 | * @return 145 | * @throws IOException 146 | */ 147 | boolean deleteColumn(String tableName, String family, String rowKey, String column) throws IOException; 148 | 149 | /** 150 | * 删除列簇下的某一列 151 | * 152 | * @param tableName 153 | * @param family 154 | * @param rowKey 155 | * @param columns 156 | * @return 157 | * @throws IOException 158 | */ 159 | boolean deleteColumn(String tableName, String family, String rowKey, List columns) throws IOException; 160 | 161 | /** 162 | * 获取连接对象 163 | * 164 | * @return 165 | */ 166 | Connection getConnection(); 167 | } 168 | -------------------------------------------------------------------------------- /src/main/java/com/yaoqi/hbase/component/template/HBaseTemplate.java: -------------------------------------------------------------------------------- 1 | package com.yaoqi.hbase.component.template; 2 | 3 | import com.yaoqi.hbase.component.assertion.Assert; 4 | import com.yaoqi.hbase.component.config.HBaseConfig; 5 | import com.yaoqi.hbase.component.constant.CommonConstant; 6 | import com.yaoqi.hbase.component.constant.ExceptionMessage; 7 | import com.yaoqi.hbase.component.operations.HBaseOperations; 8 | import org.apache.commons.lang.StringUtils; 9 | import org.apache.hadoop.hbase.HColumnDescriptor; 10 | import org.apache.hadoop.hbase.HTableDescriptor; 11 | import org.apache.hadoop.hbase.TableName; 12 | import org.apache.hadoop.hbase.client.*; 13 | import org.apache.hadoop.hbase.util.Bytes; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.stereotype.Component; 18 | 19 | import java.io.IOException; 20 | import java.util.Arrays; 21 | import java.util.List; 22 | 23 | /** 24 | * @author YaoQi 25 | * Date 2018HBaseApp/8/13 14:05 26 | * Modified 27 | * Description 28 | */ 29 | @Component 30 | public class HBaseTemplate implements HBaseOperations { 31 | 32 | private static final Logger logger = LoggerFactory.getLogger(HBaseTemplate.class); 33 | 34 | @Autowired 35 | private HBaseConfig hBaseConfig; 36 | 37 | /** 38 | * 判断表名是否存在 39 | * 40 | * @param tableName 表名 String ,注意这里区分大小写 41 | * @return 42 | */ 43 | @Override 44 | public boolean tableExists(String tableName) { 45 | Table table = null; 46 | boolean tableExistsFlag = false; 47 | Connection connection = hBaseConfig.getConnection(); 48 | try (Admin admin = connection.getAdmin()) { 49 | table = connection.getTable(TableName.valueOf(tableName)); 50 | tableExistsFlag = admin.tableExists(table.getName()); 51 | } catch (IOException e) { 52 | logger.error("IOException : {}", e.getMessage()); 53 | } finally { 54 | closeTable(table); 55 | } 56 | return tableExistsFlag; 57 | } 58 | 59 | /** 60 | * 通过表名和rowKey获取数据,获取一条数据 61 | * 62 | * @param tableName 表名 63 | * @param rowKeyVar rowKey 泛型 可支持多种类型{String,Long,Double} 64 | * @return Result 类型 65 | */ 66 | @Override 67 | public Result queryByTableNameAndRowKey(String tableName, T rowKeyVar) { 68 | Assert.notNullBatch(tableName, rowKeyVar); 69 | Assert.hasLength(tableName); 70 | boolean tableExists = tableExists(tableName); 71 | if (!tableExists) { 72 | logger.info("{}" + ExceptionMessage.TABLE_NOT_EXISTS_MSG, tableName); 73 | return null; 74 | } 75 | byte[] rowKey = checkType(rowKeyVar); 76 | Result result = null; 77 | Table table = null; 78 | try { 79 | Connection connection = hBaseConfig.getConnection(); 80 | table = connection.getTable(TableName.valueOf(tableName)); 81 | Get get = new Get(rowKey); 82 | result = table.get(get); 83 | } catch (IOException e) { 84 | logger.error("IOException : {}", e.getMessage()); 85 | } finally { 86 | closeTable(table); 87 | } 88 | return result; 89 | } 90 | 91 | /** 92 | * 自定义查询 93 | * 94 | * @param tableName 表名 95 | * @param getList 请求体 96 | * @return Result类型 97 | */ 98 | @Override 99 | public Result[] query(String tableName, List getList) { 100 | Assert.notNullBatch(tableName, getList); 101 | Assert.hasLength(tableName); 102 | boolean tableExists = tableExists(tableName); 103 | if (!tableExists) { 104 | logger.info("{}" + ExceptionMessage.TABLE_NOT_EXISTS_MSG, tableName); 105 | return null; 106 | } 107 | Table table = null; 108 | Result[] result = null; 109 | try { 110 | Connection connection = hBaseConfig.getConnection(); 111 | table = connection.getTable(TableName.valueOf(tableName)); 112 | result = table.get(getList); 113 | } catch (IOException e) { 114 | logger.error("query error , message:{}", e.getMessage()); 115 | } finally { 116 | closeTable(table); 117 | } 118 | return result; 119 | } 120 | 121 | 122 | /** 123 | * 传入一个泛型V 判断基本类型,返回对应的byte数组 124 | * 125 | * @param rowKeyVar 泛型rowKey 126 | * @param 泛型 127 | * @return 返回格式化后的字节数组 128 | */ 129 | private byte[] checkType(V rowKeyVar) { 130 | byte[] rowKey = new byte[0]; 131 | //判断T的类型 132 | String rowKeyType = rowKeyVar.getClass().getTypeName(); 133 | logger.info("rowKey Type is : {}", rowKeyType); 134 | if (String.class.getName().equals(rowKeyType)) { 135 | rowKey = Bytes.toBytes((String) rowKeyVar); 136 | } 137 | if (Long.class.getName().equals(rowKeyType)) { 138 | rowKey = Bytes.toBytes((Long) rowKeyVar); 139 | } 140 | if (Double.class.getName().equals(rowKeyType)) { 141 | rowKey = Bytes.toBytes((Double) rowKeyVar); 142 | } 143 | if (Integer.class.getName().equals(rowKeyType)) { 144 | rowKey = Bytes.toBytes((Integer) rowKeyVar); 145 | } 146 | 147 | return rowKey; 148 | } 149 | 150 | /** 151 | * 关闭连接 152 | * 153 | * @param table 表名 154 | */ 155 | private void closeTable(Table table) { 156 | if (table != null) { 157 | try { 158 | table.close(); 159 | } catch (IOException e) { 160 | logger.error("close table {} error {}", table.getName(), e.getMessage()); 161 | } 162 | } else { 163 | logger.info("table is null"); 164 | } 165 | } 166 | 167 | /** 168 | * 创建一张表 169 | * 170 | * @param tableName 表名 171 | * @param familyName 列族名 172 | */ 173 | @Override 174 | public void createTable(String tableName, String... familyName) { 175 | createTable(tableName, Arrays.asList(familyName), null); 176 | } 177 | 178 | /** 179 | * 创建表 180 | * 181 | * @param tableName 182 | * @param familyName 183 | * @param splitKeys 184 | */ 185 | @Override 186 | public void createTable(String tableName, List familyName, byte[][] splitKeys) { 187 | Assert.notNullBatch(tableName, familyName); 188 | Assert.hasLength(tableName); 189 | TableName tableNameVar = TableName.valueOf(tableName); 190 | if (!tableExists(tableName)) { 191 | HTableDescriptor hTableDescriptor = new HTableDescriptor(tableNameVar); 192 | for (String aFamilyName : familyName) { 193 | HColumnDescriptor hColumnDescriptor = new HColumnDescriptor(aFamilyName); 194 | hColumnDescriptor.setBlockCacheEnabled(true); 195 | hColumnDescriptor.setPrefetchBlocksOnOpen(true); 196 | hTableDescriptor.addFamily(hColumnDescriptor); 197 | } 198 | Connection connection = hBaseConfig.getConnection(); 199 | try (Admin admin = connection.getAdmin()) { 200 | if (splitKeys != null) { 201 | admin.createTable(hTableDescriptor, splitKeys); 202 | } else { 203 | admin.createTable(hTableDescriptor); 204 | } 205 | } catch (IOException e) { 206 | logger.error("create failed , Exception: {}", e.getMessage()); 207 | } 208 | } else { 209 | throw new IllegalArgumentException(ExceptionMessage.TABLE_ALREADY_EXISTS_MSG); 210 | } 211 | } 212 | 213 | /** 214 | * 新增一条数据 215 | * 216 | * @param tableName 目标数据表 217 | * @param rowName rowKey 218 | * @param familyName 列族名 219 | * @param qualifier 列名 220 | * @param data 字节数组类型的数据 221 | */ 222 | @Override 223 | public void put(String tableName, String rowName, String familyName, String qualifier, byte[] data) { 224 | Assert.notNullBatch(tableName, rowName, familyName, qualifier); 225 | Assert.hasLengthBatch(tableName, rowName, familyName, qualifier); 226 | Table table = null; 227 | if (tableExists(tableName)) { 228 | try { 229 | Connection connection = hBaseConfig.getConnection(); 230 | table = connection.getTable(TableName.valueOf(tableName)); 231 | Put put = new Put(Bytes.toBytes(rowName)); 232 | put.addColumn(Bytes.toBytes(familyName), Bytes.toBytes(qualifier), data); 233 | table.put(put); 234 | } catch (IOException e) { 235 | logger.error("data put error,message: {}", e.getMessage()); 236 | } finally { 237 | closeTable(table); 238 | } 239 | } else { 240 | throw new IllegalArgumentException(ExceptionMessage.TABLE_NOT_EXISTS_MSG); 241 | } 242 | } 243 | 244 | /** 245 | * 批量插入数据 246 | * 247 | * @param tableName 表名 248 | * @param putList put集合 249 | */ 250 | @Override 251 | public void putBatch(String tableName, List putList) throws IOException { 252 | Assert.notNull(putList); 253 | Assert.hasLength(tableName); 254 | // 限制最大插入数量 255 | if (putList.size() > CommonConstant.BATCH_PUT_LIMIT) { 256 | logger.warn("putList is too large to insert, {} is limit,The real size is {}", 257 | CommonConstant.BATCH_PUT_LIMIT, putList.size()); 258 | } else { 259 | Table table = null; 260 | if (tableExists(tableName)) { 261 | try { 262 | Connection connection = hBaseConfig.getConnection(); 263 | table = connection.getTable(TableName.valueOf(tableName)); 264 | table.put(putList); 265 | } catch (IOException e) { 266 | logger.error("data put error, message:{}", e.getMessage()); 267 | throw new IOException(e); 268 | } finally { 269 | closeTable(table); 270 | } 271 | } else { 272 | throw new IllegalArgumentException(ExceptionMessage.TABLE_NOT_EXISTS_MSG); 273 | } 274 | } 275 | } 276 | 277 | /** 278 | * 删除一个列族下的数据 279 | * 280 | * @param tableName 目标数据表 281 | * @param rowName rowKey 282 | * @param familyName 列族名 283 | */ 284 | @Override 285 | public void delete(String tableName, String rowName, String familyName) { 286 | delete(tableName, rowName, familyName, null); 287 | } 288 | 289 | /** 290 | * 删除某个列下的数据 291 | * 292 | * @param tableName 目标数据表 293 | * @param rowName rowKey 294 | * @param familyName 列族名 295 | * @param qualifier 列名 296 | */ 297 | @Override 298 | public void delete(String tableName, String rowName, String familyName, String qualifier) { 299 | Assert.notNullBatch(tableName, rowName, familyName); 300 | Assert.hasLengthBatch(tableName, rowName, familyName); 301 | Table table = null; 302 | try { 303 | Connection connection = hBaseConfig.getConnection(); 304 | table = connection.getTable(TableName.valueOf(tableName)); 305 | Delete delete = new Delete(rowName.getBytes()); 306 | if (qualifier != null) { 307 | delete.addColumn(familyName.getBytes(), qualifier.getBytes()); 308 | } 309 | table.delete(delete); 310 | } catch (IOException e) { 311 | logger.error("data delete error, message:{}", e.getMessage()); 312 | } finally { 313 | closeTable(table); 314 | } 315 | } 316 | 317 | /** 318 | * 批量删除数据 319 | * 320 | * @param tableName 表名 321 | * @param deleteList 需要删除的数据 322 | */ 323 | @Override 324 | public void deleteBatch(String tableName, List deleteList) { 325 | Assert.notNull(tableName); 326 | Assert.hasLength(tableName); 327 | Table table = null; 328 | try { 329 | Connection connection = hBaseConfig.getConnection(); 330 | table = connection.getTable(TableName.valueOf(tableName)); 331 | table.delete(deleteList); 332 | } catch (IOException e) { 333 | logger.error("data delete error, message:{}", e.getMessage()); 334 | } finally { 335 | closeTable(table); 336 | } 337 | } 338 | 339 | /** 340 | * 通过scan查询数据 341 | * 342 | * @param tableName 表名 343 | * @param scan scan 344 | * @return 返回 ResultScanner 345 | */ 346 | @Override 347 | public ResultScanner queryByScan(String tableName, Scan scan) { 348 | Assert.notNullBatch(tableName, scan); 349 | Assert.hasLength(tableName); 350 | ResultScanner resultScanner = null; 351 | Table table = null; 352 | try { 353 | Connection connection = hBaseConfig.getConnection(); 354 | table = connection.getTable(TableName.valueOf(tableName)); 355 | resultScanner = table.getScanner(scan); 356 | } catch (IOException e) { 357 | logger.error("query error, message:{}", e.getMessage()); 358 | } finally { 359 | closeTable(table); 360 | } 361 | return resultScanner; 362 | } 363 | 364 | /** 365 | * 删除表 366 | * 367 | * @param tableName 表名称 368 | */ 369 | @Override 370 | public void dropTable(String tableName) { 371 | boolean tableExists = tableExists(tableName); 372 | if (tableExists) { 373 | Connection connection = hBaseConfig.getConnection(); 374 | try (Admin admin = connection.getAdmin()) { 375 | admin.disableTable(TableName.valueOf(tableName)); 376 | admin.deleteTable(TableName.valueOf(tableName)); 377 | logger.info("table {} delete successfully", tableName); 378 | } catch (IOException e) { 379 | logger.error("class:[{}] method:[{}] excuter throw exception:[{}]", this.getClass().getName(), "dropTable", e.getMessage()); 380 | } 381 | } else { 382 | logger.info("table {} is not exists", tableName); 383 | } 384 | } 385 | 386 | /** 387 | * 批量删除表 388 | * 389 | * @param tableNames 390 | */ 391 | @Override 392 | public void dropTable(List tableNames) { 393 | Connection connection = hBaseConfig.getConnection(); 394 | try (Admin admin = connection.getAdmin()) { 395 | tableNames.stream().distinct().forEach(tableName -> { 396 | boolean tableExists = tableExists(tableName); 397 | if (tableExists) { 398 | try { 399 | admin.disableTable(TableName.valueOf(tableName)); 400 | admin.deleteTable(TableName.valueOf(tableName)); 401 | logger.info("table {} delete successfully", tableName); 402 | } catch (IOException e) { 403 | } 404 | } else { 405 | logger.info("table {} is not exists", tableName); 406 | } 407 | }); 408 | } catch (IOException e) { 409 | logger.error("class:[{}] method:[{}] excuter throw exception:[{}]", this.getClass().getName(), "dropTable", e.getMessage()); 410 | } 411 | } 412 | 413 | /** 414 | * 清空表 415 | * 416 | * @param tableName 417 | * @throws IOException 418 | */ 419 | @Override 420 | public void truncateTable(String tableName) throws IOException { 421 | boolean tableExists = tableExists(tableName); 422 | if (tableExists) { 423 | Connection connection = hBaseConfig.getConnection(); 424 | Admin admin = connection.getAdmin(); 425 | admin.disableTable(TableName.valueOf(tableName)); 426 | admin.truncateTable(TableName.valueOf(tableName), false); 427 | logger.info("table {} truncate successfully", tableName); 428 | } else { 429 | logger.info("table {} is not exists", tableName); 430 | } 431 | } 432 | 433 | /** 434 | * 删除某列 435 | * 436 | * @param tableName 437 | * @param family 438 | * @param rowKey 439 | * @param column 440 | * @return 441 | * @throws IOException 442 | */ 443 | @Override 444 | public boolean deleteColumn(String tableName, String family, String rowKey, String column) throws IOException { 445 | return this.deleteColumn(tableName, family, rowKey, Arrays.asList(column)); 446 | } 447 | 448 | /** 449 | * 删除某些列 450 | * 451 | * @param tableName 452 | * @param family 453 | * @param rowKey 454 | * @param columns 455 | * @return 456 | * @throws IOException 457 | */ 458 | @Override 459 | public boolean deleteColumn(String tableName, String family, String rowKey, List columns) throws IOException { 460 | if (StringUtils.isBlank(tableName) || StringUtils.isBlank(family) || StringUtils.isBlank(rowKey)) { 461 | logger.info("parameter is error"); 462 | return false; 463 | } 464 | if (columns.isEmpty()) { 465 | logger.info("columns is empty"); 466 | return false; 467 | } 468 | boolean tableExists = tableExists(tableName); 469 | if (tableExists) { 470 | Connection connection = hBaseConfig.getConnection(); 471 | Table table = connection.getTable(TableName.valueOf(tableName)); 472 | Delete delete = new Delete(rowKey.getBytes()); 473 | for (String column : columns) { 474 | delete.addColumn(family.getBytes(), column.getBytes()); 475 | } 476 | table.delete(delete); 477 | logger.info("table {} truncate successfully", tableName); 478 | return true; 479 | } else { 480 | logger.info("table {} is not exists", tableName); 481 | return false; 482 | } 483 | } 484 | 485 | /** 486 | * 获取连接对象 487 | * 488 | * @return 489 | */ 490 | @Override 491 | public Connection getConnection() { 492 | return hBaseConfig.getConnection(); 493 | } 494 | } 495 | -------------------------------------------------------------------------------- /src/test/java/com/yaoqi/hbase/component/assertion/AssertTest.java: -------------------------------------------------------------------------------- 1 | package com.yaoqi.hbase.component.assertion; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @Author YaoQi 7 | * @Date 2018/8/13 17:17 8 | * @Modified 9 | * @Description 10 | */ 11 | public class AssertTest { 12 | 13 | @Test 14 | public void hasLengthBatch() { 15 | 16 | } 17 | 18 | @Test 19 | public void notNullBatch() { 20 | Object a = null; 21 | String[] b = {"a", "b"}; 22 | Assert.notNullBatch(a, b); 23 | } 24 | 25 | @Test 26 | public void testStr() { 27 | String a = "aa"; 28 | String b = "aa"; 29 | System.out.println(b.contains(a)); 30 | } 31 | 32 | public static void main(String[] args) { 33 | for (;;){ 34 | System.out.println("fuck"); 35 | } 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /src/test/java/com/yaoqi/hbase/component/template/HBaseTemplateTest.java: -------------------------------------------------------------------------------- 1 | package com.yaoqi.hbase.component.template; 2 | 3 | import com.yaoqi.hbase.component.HBaseApp; 4 | import com.yaoqi.hbase.component.operations.HBaseOperations; 5 | import org.apache.hadoop.hbase.CellUtil; 6 | import org.apache.hadoop.hbase.client.*; 7 | import org.apache.hadoop.hbase.filter.*; 8 | import org.apache.hadoop.hbase.util.Bytes; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.test.context.junit4.SpringRunner; 14 | 15 | import java.io.IOException; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | /** 20 | * @Author YaoQi 21 | * @Date 2018/8/14 11:31 22 | * @Modified 23 | * @Description 24 | */ 25 | @RunWith(SpringRunner.class) 26 | @SpringBootTest(classes = HBaseApp.class) 27 | public class HBaseTemplateTest { 28 | 29 | @Autowired 30 | private HBaseOperations hBaseDao; 31 | 32 | @Autowired 33 | private HBaseAdmin hBaseAdmin; 34 | 35 | /** 36 | * 查询测试 37 | */ 38 | @Test 39 | public void testQueryTable() { 40 | Result result = hBaseDao.queryByTableNameAndRowKey("LBS", 9223372036854775803L); 41 | System.out.println(result.isEmpty()); 42 | result.listCells().forEach(cell -> { 43 | System.out.println("row:" + Bytes.toLong(CellUtil.cloneRow(cell)) + " family:" 44 | + Bytes.toString(CellUtil.cloneFamily(cell)) + " qualifier: " + Bytes.toString(CellUtil.cloneQualifier(cell)) 45 | + " value:" + Bytes.toString(CellUtil.cloneValue(cell))); 46 | }); 47 | } 48 | 49 | @Test 50 | public void testQuery() { 51 | String tableName = "HBase-component"; 52 | String rowKey = "1534154424340"; 53 | Get get = new Get(rowKey.getBytes()); 54 | List getList = new ArrayList<>(); 55 | getList.add(get); 56 | System.out.println(hBaseDao.query(tableName, getList).length); 57 | } 58 | 59 | /** 60 | * 创建表测试 61 | */ 62 | @Test 63 | public void testCreateTable() { 64 | hBaseDao.createTable("HBase-component", "CF1", "CF2"); 65 | } 66 | 67 | /** 68 | * 删除表测试 69 | */ 70 | @Test 71 | public void deleteTable() { 72 | hBaseDao.dropTable("HBase-component_1"); 73 | } 74 | 75 | /** 76 | * 判断表是否存在 77 | */ 78 | @Test 79 | public void testTableExist() { 80 | System.out.println(hBaseDao.tableExists("lbs")); 81 | System.out.println(hBaseDao.tableExists("LBS")); 82 | System.out.println(hBaseDao.tableExists("goods")); 83 | System.out.println(hBaseDao.tableExists("GOODS")); 84 | } 85 | 86 | /** 87 | * 插入一条记录 88 | */ 89 | @Test 90 | public void putTest() { 91 | String rowKey = String.valueOf(System.currentTimeMillis()); 92 | hBaseDao.put("HBase-component", "1534154424340", "CF1", "test_1", Bytes.toBytes("testData")); 93 | } 94 | 95 | /** 96 | * 批量插入数据 97 | */ 98 | @Test 99 | public void testBatchPut() throws IOException { 100 | String rowKey = String.valueOf(System.currentTimeMillis()); 101 | Put put = new Put(rowKey.getBytes()); 102 | String defaultColumn = "CF1"; 103 | String column1 = "col1"; 104 | String column2 = "col2"; 105 | String column3 = "col3"; 106 | 107 | String value = "test"; 108 | put.addColumn(defaultColumn.getBytes(), column1.getBytes(), value.getBytes()); 109 | put.addColumn(defaultColumn.getBytes(), column2.getBytes(), value.getBytes()); 110 | put.addColumn(defaultColumn.getBytes(), column3.getBytes(), value.getBytes()); 111 | 112 | List putList = new ArrayList<>(); 113 | putList.add(put); 114 | putList.add(put); 115 | putList.add(put); 116 | putList.add(put); 117 | putList.add(put); 118 | 119 | hBaseDao.putBatch("HBase-component", putList); 120 | } 121 | 122 | @Test 123 | public void deleteTest() { 124 | hBaseDao.delete("HBase-component", "1534210201115", "CF1", "col2"); 125 | } 126 | 127 | @Test 128 | public void deleteBatchTest() { 129 | String tableName = "HBase-component"; 130 | String rowKey1 = "1534164113922"; 131 | String rowKey2 = "1534168248328"; 132 | 133 | List deleteList = new ArrayList<>(); 134 | Delete delete = new Delete(rowKey1.getBytes()); 135 | Delete delete1 = new Delete(rowKey2.getBytes()); 136 | deleteList.add(delete); 137 | deleteList.add(delete1); 138 | hBaseDao.deleteBatch(tableName, deleteList); 139 | } 140 | 141 | @Test 142 | public void testQueryScan() { 143 | 144 | String tableName = "RECOMMEND_ENGINE_DATA_MODEL"; 145 | List timestampList = new ArrayList<>(); 146 | Long timeDifference = 3L * 30L * 24L * 60L * 60L * 1000L; 147 | Long from = System.currentTimeMillis() - timeDifference; 148 | timestampList.add(from); 149 | TimestampsFilter timestampsFilter = new TimestampsFilter(timestampList); 150 | 151 | Scan scan = new Scan(); 152 | try { 153 | scan.setTimeRange(from, System.currentTimeMillis()); 154 | } catch (IOException e) { 155 | e.printStackTrace(); 156 | } 157 | 158 | ResultScanner resultScanner = hBaseDao.queryByScan(tableName, scan); 159 | 160 | resultScanner.forEach(result -> { 161 | result.listCells().forEach(cell -> { 162 | System.out.println("row:" + Bytes.toLong(CellUtil.cloneRow(cell)) + " family:" 163 | + Bytes.toString(CellUtil.cloneFamily(cell)) + " qualifier: " + Bytes.toString(CellUtil.cloneQualifier(cell)) 164 | + " value:" + Bytes.toString(CellUtil.cloneValue(cell))); 165 | 166 | }); 167 | }); 168 | } 169 | 170 | @Test 171 | public void testPageFilter() { 172 | String tableName = "HBase-component"; 173 | Scan scan = new Scan(); 174 | 175 | PageFilter pageFilter = new PageFilter(1); 176 | 177 | SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter( 178 | "CF1".getBytes(), 179 | "col1".getBytes(), 180 | CompareFilter.CompareOp.EQUAL, 181 | new SubstringComparator("group")); 182 | 183 | singleColumnValueFilter.setFilterIfMissing(true); 184 | FilterList filterList = new FilterList(); 185 | filterList.addFilter(singleColumnValueFilter); 186 | filterList.addFilter(pageFilter); 187 | 188 | scan.setFilter(filterList); 189 | 190 | ResultScanner resultScanner = hBaseDao.queryByScan(tableName, scan); 191 | 192 | try { 193 | resultScanner.forEach(result -> { 194 | result.listCells().forEach(cell -> { 195 | System.out.println("row:" + Bytes.toString(CellUtil.cloneRow(cell)) + " family:" 196 | + Bytes.toString(CellUtil.cloneFamily(cell)) + " qualifier: " + Bytes.toString(CellUtil.cloneQualifier(cell)) 197 | + " value:" + Bytes.toString(CellUtil.cloneValue(cell))); 198 | 199 | }); 200 | }); 201 | } finally { 202 | if (resultScanner != null) { 203 | resultScanner.close(); 204 | } 205 | } 206 | } 207 | } -------------------------------------------------------------------------------- /src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | # HBase配置 2 | HBase: 3 | conf: 4 | quorum: 192.168.90.201:2181,192.168.90.202:2181,192.168.90.203:2181,192.168.90.204:2181 5 | znodeParent: /hbase-unsecure 6 | # config: 7 | # #keytab地址路径 8 | # user-keytab: D:\java\work\auth\hbase\test-hbase-kb\root.keytab 9 | # #如果使用kb认证请写以下kerberos否则不用写 10 | # authMethod: kerberos 11 | # #master.kerberos.principal 12 | # masterPrincipal: root/hadoop-beta-01@SEMPTIAN.COM 13 | # #regionserver.kerberos.principal regionserverPrincipal/hbaseSitePath 二选一,一些环境下使用hbaseSitePath更简单 14 | # #regionserverPrincipal: root/_HOST@SEMPTIAN.COM 15 | # #hbseSite配置文件路径D:\kerberos\hbase-kb\hbase-site.xml 16 | # hbaseSitePath: D:\java\work\auth\hbase\test-hbase-kb\hbase-site.xml 17 | # #coreSitePath: D:\kerberos\dev-hbase-kb\core-site.xml --------------------------------------------------------------------------------