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',
` rule` varchar (255) NOT NULL COMMENT'prefix prefix ',
`length`bigint (20) NOT NULL
COMMENT'length ', `init_value`bigint (20) NOT NULL
COMMENT'initial value ', `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 ' 버전 번호', PRIMARY KEY (`id`) USING BTREE
) 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;
}
}