在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;
    }

}

posted @ 2022-04-24 22:36  行舟QAQ  阅读(1271)  评论(1编辑  收藏  举报