创建表格存储 client,在接口代码中直接注入 即可使用 ( @Autowired @Qualifier("createClient") private SyncClient client;) package com.mimidai.common.utils.table;import com.alicloud.openservices.tablestore.ClientConfigurati
package com.mimidai.common.utils.table; import com.alicloud.openservices.tablestore.ClientConfiguration; import com.alicloud.openservices.tablestore.SyncClient; import com.alicloud.openservices.tablestore.model.AlwaysRetryStrategy; import com.mimidai.common.utils.PropertiesUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 创建表格存储client Created by EVE on 2017-06-22. */ @Configuration //@PropertySource("classpath:application-develop.properties") public class TableClientConfig { private static Logger logger = LoggerFactory.getLogger("log.hbase.TableClientConfig"); //测试 环境 start //内网地址 private String endPoint = "http://XXXXXX:80/"; //外网地址 网段地址保留一个即可 // private static final String endPoint = "http://XXXXXX.cn-beijing.ots.aliyuncs.com"; private String accessId = "XXXXXX"; private String accessKey = "XXXXXXXX"; private String instanceName = "test"; //测试 @Bean public SyncClient createClient() { try{ logger.info("开始调用createClient方法"); // ClientConfiguration提供了很多配置项,以下只列举部分。 ClientConfiguration clientConfiguration = new ClientConfiguration(); // 设置建立连接的超时时间。 clientConfiguration.setConnectionTimeoutInMillisecond(5000); // 设置socket超时时间。 clientConfiguration.setSocketTimeoutInMillisecond(5000); // 设置重试策略,若不设置,采用默认的重试策略。 clientConfiguration.setRetryStrategy(new AlwaysRetryStrategy()); logger.info("返回创建表格存储cleint"); return new SyncClient(endPoint, accessId, accessKey, instanceName, clientConfiguration); } catch (Exception e) { logger.warn("----------------------表格存储client初始化失败"); } return null; } }创建表格存储表的工具类,可通过此创建带版本的表。(在官方客户端好像不可以创建版本,我是没发现)
package com.mimidai.common.utils.table; import com.alicloud.openservices.tablestore.SyncClient; import com.alicloud.openservices.tablestore.model.CapacityUnit; import com.alicloud.openservices.tablestore.model.DeleteTableRequest; import com.alicloud.openservices.tablestore.model.DescribeTableRequest; import com.alicloud.openservices.tablestore.model.DescribeTableResponse; import com.alicloud.openservices.tablestore.model.PrimaryKeySchema; import com.alicloud.openservices.tablestore.model.PrimaryKeyType; import com.alicloud.openservices.tablestore.model.ReservedThroughput; import com.alicloud.openservices.tablestore.model.ReservedThroughputDetails; import com.alicloud.openservices.tablestore.model.TableMeta; import com.alicloud.openservices.tablestore.model.TableOptions; import com.alicloud.openservices.tablestore.model.UpdateTableRequest; import com.alicloud.openservices.tablestore.model.internal.CreateTableRequestEx; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; /** * Created by 孟庆艺 on 2017-08-03. */ @Service public class OperateTableUtils { @Autowired @Qualifier("createClient") private SyncClient client; private static final Logger logger = LoggerFactory.getLogger("log.tableStore.OperateTableUtils"); /** * 创建表 * * @param createTableName 表名 * @param timeToLive 数据过期时间 单位:秒 例如:一年 365*24*3600 -1表示永不过期 * @param maxVersions 保存最大版本数 设置为3即代表每列最多保存 N 个最新的版本 * @param primaryKey 可变参数类型 主键列名 可变参数最大为4 */ public void createTable(String createTableName, Integer timeToLive, Integer maxVersions, String... primaryKey) { if (primaryKey.length > 4) { logger.info("注意:表格存储主键最多可设置4个,可变参数个数最大为4"); return; } TableMeta tableMeta = new TableMeta(createTableName); for (String PRIMARY_KEY : primaryKey) { tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema(PRIMARY_KEY, PrimaryKeyType.STRING)); } TableOptions tableOptions = new TableOptions(timeToLive, maxVersions); CreateTableRequestEx request = new CreateTableRequestEx(tableMeta, tableOptions); //设置读写预留值 容量型示例 只能设置为0 高性能示例可以设置为非零值 request.setReservedThroughput(new ReservedThroughput(new CapacityUnit(0, 0))); client.createTable(request); } /** * 创建表 * * @param timeToLive 数据过期时间 单位:秒 例如:一年 365*24*3600 -1表示永不过期 * @param maxVersions 保存最大版本数 设置为3即代表每列最多保存 N 个最新的版本 */ public void createTable(String createTableName, Integer timeToLive, Integer maxVersions, List该方法将重点着眼于 分区键的创建,一个良好的表结构设计尤为重要,分区键关系到最大化的利用大数据量情况下表格存储,自动分区,数据均匀散列分布,有利于分布式的操作数据primaryKey) { if (primaryKey.size() > 4) { logger.info("注意:表格存储主键最多可设置4个,可变参数个数最大为4"); return; } TableMeta tableMeta = new TableMeta(createTableName); tableMeta.addPrimaryKeyColumns(primaryKey); TableOptions tableOptions = new TableOptions(timeToLive, maxVersions); CreateTableRequestEx request = new CreateTableRequestEx(tableMeta, tableOptions); //设置读写预留值 容量型示例 只能设置为0 高性能示例可以设置为非零值 request.setReservedThroughput(new ReservedThroughput(new CapacityUnit(0, 0))); client.createTable(request); } /** * 构建list */ private List primaryKeySchemaList(Object... primaryKey) { if (primaryKey.length > 4) { logger.info("注意:表格存储主键最多可设置4个,可变参数个数最大为4"); return null; } List primaryKeySchemaList = new ArrayList<>(); for (Object PRIMARYKEY : primaryKey) { if (PRIMARYKEY instanceof String) { String PRIMARY_KEY = (String) PRIMARYKEY; primaryKeySchemaList.add(new PrimaryKeySchema(PRIMARY_KEY, PrimaryKeyType.STRING)); } } return primaryKeySchemaList; } /** * 更新表 * * @param timeToLive 数据过期时间 单位:秒 例如:一年 365*24*3600 -1表示永不过期 * @param maxVersions 保存最大版本数 设置为3即代表每列最多保存 N 个最新的版本 * @param maxTimeDeviation 有效版本偏差 [数据写入时间-有效版本偏差,数据写入时间+有效版本偏差) */ public void updateTable(Integer timeToLive, Integer maxVersions, Long maxTimeDeviation, String TableName) { if (maxVersions == null || TableName == null) { return; } TableOptions tableOptions = new TableOptions(); if (maxVersions != null) { tableOptions = new TableOptions(maxVersions); } else if (timeToLive != null) { tableOptions = new TableOptions(timeToLive, maxVersions); } else if (maxTimeDeviation != null) { tableOptions = new TableOptions(timeToLive, maxVersions, maxTimeDeviation); } UpdateTableRequest updateTableRequest = new UpdateTableRequest(TableName); updateTableRequest.setTableOptionsForUpdate(tableOptions); client.updateTable(updateTableRequest); } /** * 获取表相关信息 */ public void describeTable(String TableName) { DescribeTableRequest describeStreamRequest = new DescribeTableRequest(TableName); DescribeTableResponse describeTableResponse = client.describeTable(describeStreamRequest); TableMeta tableMeta = describeTableResponse.getTableMeta(); List primaryKeySchemaList = tableMeta.getPrimaryKeyList(); for (PrimaryKeySchema primaryKeySchema : primaryKeySchemaList) { logger.info("表:{}主键:{}", TableName, primaryKeySchema); } TableOptions tableOptions = describeTableResponse.getTableOptions(); ReservedThroughputDetails reservedThroughputDetails = describeTableResponse.getReservedThroughputDetails(); logger.info("表:{},数据过期时间timeToLive:{},最大版本数maxVersions:{},预留读吞吐量:{},预留写吞吐量:{}", TableName, tableOptions .getTimeToLive(), reservedThroughputDetails.getCapacityUnit().getReadCapacityUnit(), reservedThroughputDetails.getCapacityUnit().getWriteCapacityUnit()); } /** * 删除表 */ public void deleteTable(String TableName) { DeleteTableRequest deleteTableRequest = new DeleteTableRequest(TableName); client.deleteTable(deleteTableRequest); } }
package com.mimidai.common.utils.table;/** * Created by 孟庆艺 on 2017-08-31. */ import com.alicloud.openservices.tablestore.model.PrimaryKeyBuilder; import com.alicloud.openservices.tablestore.model.PrimaryKeyValue; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sun.misc.BASE64Encoder; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Random; import com.alicloud.openservices.tablestore.model.PrimaryKey; /** * 表格存储生成构造主键方法 * * @author mengqingyi * @create 2017-08-31 10:13 **/ public class PrimaryKeyUtils { //日志 private static final Logger logger = LoggerFactory.getLogger(PrimaryKey.class); /** * 使用md5算法加密算法 对字符串进行加密 */ private String EncodeByMd5(String string) throws NoSuchAlgorithmException, UnsupportedEncodingException { //计算方法 MessageDigest messageDigest = MessageDigest.getInstance("MD5"); BASE64Encoder base64Encoder = new BASE64Encoder(); //加密后的字符串 String newStr = base64Encoder.encode(messageDigest.digest(string.getBytes("UTF-8"))); return newStr; } /** * 如有明确的分区键,则可以使用分区键+主键格式构造主键 */ public PrimaryKey createPrimaryKey(Integer partitionKey, String userId) { logger.debug("进入tableStore(core1)生成构造主键通用方法createPrimaryKey"); // 首先对入参进行判断 若为空直接返回 不再查询 if (StringUtils.isBlank(partitionKey + "") || StringUtils.isBlank(userId)) { logger.warn("表格存储短信详单主键为空,达不到构造主键要求,返回空值"); return null; } // 构造主键 PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder(); primaryKeyBuilder.addPrimaryKeyColumn("partitionKey", PrimaryKeyValue.fromLong(partitionKey)); primaryKeyBuilder.addPrimaryKeyColumn("userId", PrimaryKeyValue.fromString(userId)); logger.info("tableStore(core1)生成构造主键通用方法createPrimaryKey:partitionKey={},userId={}", partitionKey, userId); return primaryKeyBuilder.build(); } /** * 如无明确的分区键,方案1.由大小为5随机桶(实际就是随机数)作为分区键 以桶的随机数作为分片键(表格存储,hbase中也有类似方案,salted key) */ public PrimaryKey createPrimaryKeyByRandomBucket(String userId) { logger.debug("进入tableStore(core1)生成构造主键通用方法createPrimaryKey"); // 首先对入参进行判断 若为空直接返回 不再查询 if (StringUtils.isBlank(userId)) { logger.warn("表格存储短信详单主键为空,达不到构造主键要求,返回空值"); return null; } Integer partitionKey = new Random().nextInt(5); // 构造主键 PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder(); primaryKeyBuilder.addPrimaryKeyColumn("partitionKey", PrimaryKeyValue.fromLong(partitionKey)); primaryKeyBuilder.addPrimaryKeyColumn("userId", PrimaryKeyValue.fromString(userId)); logger.info("tableStore(core1)生成构造主键通用方法createPrimaryKey:partitionKey={},userId={}", partitionKey, userId); return primaryKeyBuilder.build(); } /** * 如无明确的分区键,方案1.指定大小的随机桶(实际就是随机数)作为分区键 以桶的随机数作为分片键(表格存储,hbase中也有类似方案,salted key) */ public PrimaryKey createPrimaryKeyByRandomBucket(String userId, Integer randomBucketSize) { logger.debug("进入tableStore(core1)生成构造主键通用方法createPrimaryKey"); // 首先对入参进行判断 若为空直接返回 不再查询 if (StringUtils.isBlank(userId)) { logger.warn("表格存储短信详单主键为空,达不到构造主键要求,返回空值"); return null; } Integer partitionKey = new Random().nextInt(randomBucketSize); // 构造主键 PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder(); primaryKeyBuilder.addPrimaryKeyColumn("partitionKey", PrimaryKeyValue.fromLong(partitionKey)); primaryKeyBuilder.addPrimaryKeyColumn("userId", PrimaryKeyValue.fromString(userId)); logger.info("tableStore(core1)生成构造主键通用方法createPrimaryKey:partitionKey={},userId={}", partitionKey, userId); return primaryKeyBuilder.build(); } /** * 无明确的分区键,取散裂化后的userId的前4位作为分区键 */ public PrimaryKey createPrimaryKeyByUserId(String userId) { logger.debug("进入tableStore(core1)生成构造主键通用方法createPrimaryKey"); // 首先对入参进行判断 若为空直接返回 不再查询 if (StringUtils.isBlank(userId)) { logger.warn("表格存储短信详单主键为空,达不到构造主键要求,返回空值"); return null; } String partitionKey = null; try { partitionKey = EncodeByMd5(userId); logger.info("userId={},MD5之后的md5UserId={}", userId, partitionKey); } catch (Exception e) { e.printStackTrace(); } // 构造主键 PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder(); primaryKeyBuilder.addPrimaryKeyColumn("partitionKey", PrimaryKeyValue.fromString(partitionKey)); primaryKeyBuilder.addPrimaryKeyColumn("userId", PrimaryKeyValue.fromString(userId)); logger.info("tableStore(core1)生成构造主键通用方法createPrimaryKey:partitionKey={},userId={}", partitionKey, userId); return primaryKeyBuilder.build(); } }最后奉上 官方表格存储的最佳实践
https://yq.aliyun.com/articles/57102