Redisが一意のコードを生成する方法(1)

 1.関連するテーブル構造

CREATE TABLE `int_item_identity`(
  ` id` int(11)NOT NULL AUTO_INCREMENT COMMENT'ID '、
  ` name` varchar(255)NOT NULL
  COMMENT'name '、` alias` varchar(255)NOT NULL COMMENT'alias '、
  `ルール `varchar(255)NOT NULL COMMENT 'プレフィックスプレフィックス'、
  ` length` bigint(20)NOT NULL
  COMMENT '長さ'、`init_value` bigint(20)NOT NULL
  COMMENT '初期値'、` cur_value` bigint(20) NOT NULL   COMMENT
  '
現在の値'、`max_value` bigint(20)NOT NULL COMMENT '最大値'、` step` int(5)NOT NULL COMMENT 'ステップ長、毎回追加される長さ'、
  `version` int(5) NOT NULL
  COMMENT 'バージョン番号'、BTREEを使用する主キー( `id`)
)ENGINE = InnoDB AUTO_INCREMENT = 46 DEFAULT CHARSET = utf8 ROW_FORMAT = DYNAMIC COMMENT = 'カスタムコーディング範囲 ';
 

2.Redis依存関係パッケージ

         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.1.3.RELEASE</version>
        </dependency>

3.簡単なコードブロック


@Slf4j
public class BaseMapper<T> {

	/**
	 * 主键
	 */
	private final static String INT_ITEM_IDENTITY,
	KEY_FORMAT,
	MAX_ID_FORMAT,
	DATA,
	VALUE,
	EMPTY_STRING;

	/**
	 * 静态代码块
	 */
	static {
		INT_ITEM_IDENTITY = "INT_ITEM_IDENTITY";
		KEY_FORMAT = "%s:%s_%s";
		MAX_ID_FORMAT = "%s%s";
		DATA = "DATA";
		VALUE = "VALUE";
		EMPTY_STRING = "";
	}

	/**
	 * 通用的查询
	 */
	@Autowired
	protected Mapper<T> mapper;
	/**
	 * 通用的查询
	 */
	@Autowired
	protected CommonMapper commonMapper;
	/**
	 * redis 字符串操作
	 */
	@Autowired
	private RedisStringClient redisStringClient;
	/**
	 * redis set操作
	 */
	@Autowired
	private RedisClient redisClient;
	/**
	 * 自定义编码范围
	 */
	@Autowired
	private IdentityService identityService;
	/**
	 * 发送短信
	 */
	@Autowired
	private IntMessageSendService messageSendService;

	/**
	 * 获取编码,这个继承这个,传泛型
	 *
	 * @return 返回 编码
	 */
	protected String getCode() {
		return this.getCode(null);
	}

	/**
	 * 获取编码,这个继承这个,传泛型
	 *
	 * @param prefix 前缀
	 * @return 返回 编码
	 */
	protected String getCode(String prefix) {
		return this.getCode(null, null, prefix);
	}

	/**
	 * 获取编码,按照传的表名和主键
	 *
	 * @param tableName  表名
	 * @param primaryKey 主键名称
	 * @param prefix     前缀
	 * @return 返回编码
	 */
	protected String getCode(String tableName, String primaryKey, String prefix) {
		// 获取表名
		if (StringUtils.isBlank(tableName)) {
			tableName = this.getTableName();
		}

		Assert.notNull(tableName, "表名不能为空");
		IntItemIdentity intItemIdentity = getIntItemIdentity(tableName);
		Assert.notNull(intItemIdentity, "编码关系没有配置");
		if (StringUtils.isBlank(prefix)) {
			prefix = intItemIdentity.getRule();
		}
		// 获取最大值
		String maxId = getMaxId(tableName, primaryKey, prefix, intItemIdentity);
		//设置子线程共享
		ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		if (servletRequestAttributes != null) {
			// 异步更新
			identityService.updateAsync(intItemIdentity, maxId, prefix);
		}
		return maxId;
	}

	/**
	 * 获取 泛型精确类型
	 */
	protected Class<?> getActualType() {
		return getActualType(this.getClass().getGenericSuperclass());
	}

	/**
	 * 获取 泛型精确类型
	 *
	 * @param superType 类
	 * @return 返回泛型对象
	 */
	protected Class<?> getActualType(Type superType) {
		ParameterizedType paraType = (ParameterizedType) superType;
		Type[] types = paraType.getActualTypeArguments();
		for (Type type : types) {
			Annotation annotation = ((Class) type).getAnnotation(Table.class);
			if (annotation == null) {
				continue;
			}
			return (Class<?>) type;
		}
		return null;
	}

    // --- 私有方法 ---

	/**
	 * 获取实体类的表名
	 */
	private String getTableName() {
		Class<?> type = getActualType();
		Annotation annotation = type.getAnnotation(Table.class);
		if (annotation == null) {
			return null;
		}
		return ((Table) annotation).name();
	}

	/**
	 * 获取表的主键
	 */
	private String getPrimaryKey() {
		Class<?> type = getActualType();
		Annotation annotation = (type).getAnnotation(Table.class);
		if (annotation == null) {
			return null;
		}
		Field[] fields = type.getDeclaredFields();
		for (Field field : fields) {
			Id id = field.getAnnotation(Id.class);
			if (id == null) {
				continue;
			}
			Column column = field.getAnnotation(Column.class);
			if (column == null) {
				return field.getName();
			}
			return column.name();
		}
		return null;
	}

	/**
	 * 获取最大的id
	 *
	 * @param tableName       表名
	 * @param primaryKey      主键名称
	 * @param prefix          前缀
	 * @param intItemIdentity 实体对象
	 * @return 返回 最大ID
	 */
	private String getMaxId(String tableName, String primaryKey, String prefix, IntItemIdentity intItemIdentity) {
		String key = String.format(KEY_FORMAT, INT_ITEM_IDENTITY, DATA, tableName);

		Long redisMaxId = 0L;
		String maxId;
		try {
			redisMaxId = redisStringClient.getMaxId(key, intItemIdentity.getCurValue(), intItemIdentity.getStep());
			maxId = String.format(MAX_ID_FORMAT, prefix, redisMaxId);
		} catch (Exception e) {
			log.error("{}", e);
			maxId = exceptionHandle(key, primaryKey, tableName, prefix);
		}
		if (redisMaxId == null || intItemIdentity.getCurValue() == null
				|| redisMaxId <= intItemIdentity.getCurValue()) {
			// 获取最大的值
			maxId = exceptionHandle(key, primaryKey, tableName, prefix);
            // 异常提醒
             xxxxx
		}
		return maxId;
	}

	/**
	 * 异常处理
	 *
	 * @param key        key
	 * @param primaryKey 主键的字段
	 * @param tableName  表名
	 * @param prefix     前缀
	 * @return 返回最大值
	 */
	private String exceptionHandle(String key, String primaryKey, String tableName, String prefix) {
		if (StringUtils.isBlank(primaryKey)) {
			primaryKey = getPrimaryKey();
		}
		Assert.notNull(primaryKey, "表主键不能为空");
		String maxId = commonMapper.getMaxId(tableName, primaryKey);
		try {
			// 异常之后重新赋值赋值,这里会有一个问题,若是这里失败了,下次获取redis正常会导致主键冲突
			Long redisMaxId = Long.parseLong(maxId.replace(prefix, EMPTY_STRING));
			// 若是当前的值小于查询的值,那么说明应该是异常了
			redisStringClient.increment(key, redisMaxId);
			key = String.format(KEY_FORMAT, INT_ITEM_IDENTITY, VALUE, tableName);
			redisClient.delete(key);
		} catch (Exception e) {
			log.error("{}", e);
		}
		return maxId;
	}

	/**
	 * 获取 IntItemIdentity
	 *
	 * @param tableName 表名
	 * @return 返回 IntItemIdentity
	 */
	private IntItemIdentity getIntItemIdentity(String tableName) {
		String key = String.format(KEY_FORMAT, INT_ITEM_IDENTITY, VALUE, tableName);
		IntItemIdentity intItemIdentity = null;
		try {
			intItemIdentity = redisClient.getValue(key);
		} catch (Exception e) {
			log.error("{}", e);
		}
		if (intItemIdentity == null) {
			Condition<IntItemIdentity> condition = new Condition<>(IntItemIdentity.class);
			WeekendCriteria<IntItemIdentity, Object> weekendCriteria = condition.weekendCriteria();
			weekendCriteria.andEqualTo(IntItemIdentity::getName, tableName);
			intItemIdentity = commonMapper.selectOneByExample(condition);
			try {
				if (intItemIdentity == null) {
					// 为空的时候,时间稍微短一点
					redisClient.setValue(key, intItemIdentity, 30);
				} else {
					redisClient.setValue(key, intItemIdentity, 5 * 60);
				}
			} catch (Exception e) {
				log.error("{}", e);
			}
		}
		return intItemIdentity;
	}
}

 

おすすめ

転載: blog.csdn.net/qq_38428623/article/details/114404317