背景
目前遇到一个业务场景,数据库中需要存储业务状态字段,业务含义是指定三种数据源是否同步成功,但是在建立数据表的时候,设置了一个int类型的字段,如何在不改变数据库表结构的情况,满足业务需求?
初步方案
假设A/B/C三种数据源,分别使用0/1标记,分别代表成功失败,但是数据库字段只能是整数,于是就可以这样表示,使用一个四位的数字,最高位固定为1,初始化值为 1000,三种业务状态分别跟低三位一一对应 eg: A业务成功,B成功,C失败,可以表示为 1110
升级方案
上述方案,可以满足业务诉求,但是有一个问题,占用的mysql的内存比较大,因为最低的情况1000起步,可以使用二进制做一个简化,数据库中存储二进制对应的十进制数,这样存储的大小就大大的减少 eg: A业务成功,B成功,C失败,二进制表示为 110,十进制为:6,则数据库中存储十进制的数,可以大大缩小内存空间
业务升级
背景
后续发现,业务状态的枚举还有一种待同步的状态,因为每一种状态的同步是异步发生,不同时间的状态可能会不一样,这个时候需要更改一下技术方案
方案
之前使用的是一个二进制位来表示状态,因为只有成功和失败的两种状态,但是目前状态的枚举数为3,所以就使用2个二进制位来表示对应的三种状态: 00 ->未同步 01 ->成功 11 ->失败 最终来组装拼接到一起,eg: A业务成功,B成功,C失败,二进制表示为:010111 ,对应十进制为19 封装代码如下:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 任务同步业务方
*/
public class BizSyncStatusUtil {
/** 业务方状态枚举 */
public static final int NOT_SYNCED = 0; // 00
public static final int SYNC_SUCCESS = 1; // 01
public static final int SYNC_FAILED = 2; // 10
public static final int TOTAL_COUNT = 3; // 11
public static final List<String> biz_code_list = Arrays.asList("xx1", "xx2", "xx3");
/**
* 获取指定业务方的2位状态值
* @param status 整体状态字段
* @param biz 业务方编号,从0开始
* @return 0=未同步,1=成功,2=失败,3=保留
*/
public static int getBizStatus(int status, String biz) {
int bitPos = getBizIndex(biz) * 2;
return (status >> bitPos) & 0b11;
}
/**
* 校验指定业务方是否已同步(成功或失败均表示已同步)
*/
public static boolean isSynced(int status, String biz) {
int v = getBizStatus(status, biz);
return v == SYNC_SUCCESS || v == SYNC_FAILED;
}
/**
* 校验指定业务方是否同步成功
*/
public static boolean isSyncSuccess(int status, String biz) {
return getBizStatus(status, biz) == SYNC_SUCCESS;
}
/**
* 校验指定业务方是否同步失败
*/
public static boolean isSyncFailed(int status, String biz) {
return getBizStatus(status, biz) == SYNC_FAILED;
}
/**
* 校验所有业务方是否同步成功
*/
public static boolean allIsSuccess(int status) {
for (String s : DC_LIST) {
if (!isSynced(status, s)) return false;
}
return true;
}
public static boolean haveFail(int status) {
for (String s : DC_LIST) {
if (isSyncFailed(status, s)) return true;
}
return false;
}
/**
* 获取同步失败的所有业务方
* @param status
* @return
*/
public static List<String> getFailDc(Integer status){
List<String> failedBiz = new ArrayList<>();
for(int k = 0; k < 3; k++) {
int code = (status >> (k*2)) & 0b11; // 拿出第k业务方的2bit
if(code == 2){
failedBiz.add(DC_LIST.get(k)); // k业务方同步失败
}
}
return failedBiz;
}
// status: 原始整数状态
// bizIndex: 业务方编号(从0开始)
// bizStatusCode: 0=未同步, 1=同步成功, 2=同步失败, 3=其它(预留)
public static int setBizStatus(int status, String dc, int bizStatusCode) {
int bizIndex = getBizIndex(dc);
int bitPos = bizIndex * 2;
status = (status & ~(0b11 << bitPos)) | (bizStatusCode << bitPos);
return status;
}
private static int getBizIndex(String dc) {
return DC_LIST.indexOf(dc);
}
}