在Java中实现MySQL的Compress()和Uncompress()算法
在Java中实现MySQL的Compress()和Uncompress()算法
MySQL COMPRESS()函数用于压缩字符串。 COMPRESS()函数返回的值是二进制字符串。
COMPRESS()函数将非空字符串存储为未压缩字符串的four-byte长度,然后是压缩字符串。如果字符串以空格结尾,则将“.”字符添加到字符串。另外,应注意,空字符串存储为空字符串。 COMPRESS()函数接受一个参数,该参数是要压缩的字符串。
在mysql存储的某个字段过长,可以考虑使用COMPRESS() 和uncompress(),但是会占用DB端的cpu消耗,可以考虑将这部分压缩放着服务端。
下面给出了在java代码中实现compress() 和 uncopresss()逻辑
/**
* 压缩工具类
*
* @author 行舟QaQ
*/
@Slf4j
public class GZIPUtils {
private GZIPUtils() {
}
/**
* 使用zlib压缩
*
* @param data
* @return
*/
public static byte[] compressZLib(byte[] data) {
Deflater deflater = new Deflater();
deflater.setInput(data);
deflater.finish();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
byte[] buffer = new byte[1024];
while (!deflater.finished()) {
int count = deflater.deflate(buffer);
outputStream.write(buffer, 0, count);
}
try {
outputStream.close();
} catch (IOException e) {
log.error("compressZLib outputStream close error,data-->{}, e-->{}",
JSONP.toJson(data),e);
}
return outputStream.toByteArray();
}
/**
* mysql压缩加入长度
*
* @param input
* @return
*/
public static byte[] compressToMysql(String input) {
if (StringUtils.isEmpty(input)) {
return new byte[]{};
}
byte[] lengthBytes = lengthToBinary(input.length());
byte[] compressedBytes = compressZLib(input.getBytes(StandardCharsets.UTF_8));
return binaryConcat(lengthBytes, compressedBytes);
}
/**
* 长度转二进制,并且最少为4
*
* @param length
* @return
*/
private static byte[] lengthToBinary(int length) {
byte[] bytes = binaryReverse((String.valueOf(length).getBytes(StandardCharsets.UTF_8)));
byte[] newByte = new byte[4];
byte[] bytesForStorage = binaryConcat(bytes, newByte);
byte[] res = new byte[4];
for (int i = 0; i < res.length; i++) {
res[i] = bytesForStorage[i];
}
// 返回前4位
return res;
}
/**
* 合并数据
*
* @param bytes
* @param newByte
* @return
*/
private static byte[] binaryConcat(byte[] bytes, byte[] newByte) {
int length = bytes.length + newByte.length;
// Make sure the resultant value is at least 4-bytes.
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(length);
try {
outputStream.write(bytes);
outputStream.write(newByte);
} catch (IOException e) {
log.error("binaryConcat outputStream error,bytes -- > {},newByte-->{}, e-->{}",
JSONP.toJson(bytes), JSONP.toJson(newByte),e);
throw new ServiceException();
}
return outputStream.toByteArray();
}
/**
* 反转数组
*
* @param bytes
* @return
*/
private static byte[] binaryReverse(byte[] bytes) {
int length = bytes.length;
byte[] res = new byte[length];
for (int i = 0; i < bytes.length; i++) {
res[length - i - 1] = bytes[i];
}
return res;
}
/**
* zlib解压
*
* @param data
* @return
*/
public static String decompressZLib(byte[] data) {
Inflater inflater = new Inflater();
inflater.setInput(data);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
byte[] buffer = new byte[1024];
try {
while (!inflater.finished()) {
int count = inflater.inflate(buffer);
outputStream.write(buffer, 0, count);
}
outputStream.close();
} catch (Exception e) {
log.error("decompressZLib error,buffer -- > {},data-->{}, e-->{}",
JSONP.toJson(buffer), JSONP.toJson(data),e);
}
return outputStream.toString();
}
/**
* 解压入口
*
* @param input
* @return
*/
public static String uncompressMysql(byte[] input) {
if (input == null || input.length == 0) {
return "";
}
String s = decompressZLib(Arrays.copyOfRange(input, 4, input.length));
return s;
}
}