首页 > 其他分享 >openGauss/MogDB零字节问题处理

openGauss/MogDB零字节问题处理

时间:2024-04-08 15:56:11浏览次数:12  
标签:ps 字节 hex MogDB bytes str openGauss String

openGauss/MogDB 零字节问题处理
问题描述:java 应用端程序调用 GZIP 压缩类对数据进行编码压缩后入库 ,然后从数据库取出进行解压,原来再 mysql 数据库中是正常的,但迁移到 openGauss/mogdb 之后,解压出来的数据是乱码,不正常。

mysql 端表结构如下:

CREATE TABLE test (
id bigint(20) NOT NULL,
info varchar(20) NOT NULL,
info2 mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
迁移到 openGauss/MogDB 后表结构如下:

create table test(
id int,
info text,
info2 text
);
java 压缩接口方法如下:

public static String compress(String str) throws IOException {
    if (null == str || str.length() <= 0) {
        return str;
    }
    GZIPOutputStream gzip = null;
    // 创建一个新的输出流
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    try {
        // 使用默认缓冲区大小创建新的输出流
        gzip = new GZIPOutputStream(out);
        // 将字节写入此输出流
        gzip.write(str.getBytes("utf-8"));
        // 因为后台默认字符集有可能是GBK字符集,所以此处需指定一个字符集
        gzip.close();
        // 使用指定的 charsetName,通过解码字节将缓冲区内容转换为字符串
        return out.toString("ISO-8859-1");
    } finally {
        closeQuietly(gzip);
        closeQuietly(out);
    }
}

java 解压接口方法如下:

public static String unCompress(String str) throws IOException {
GZIPInputStream gzip = null;
if (null == str || str.length() <= 0) {
return str;
}
// 创建一个新的输出流
ByteArrayOutputStream out = new ByteArrayOutputStream();
// 创建一个 ByteArrayInputStream,使用 buf 作为其缓冲 区数组
ByteArrayInputStream in = new ByteArrayInputStream(str.getBytes("ISO-8859-1"));
try {
// 使用默认缓冲区大小创建新的输入流
gzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n = 0;
// 将未压缩数据读入字节数组
while ((n = gzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
// 使用指定的 charsetName,通过解码字节将缓冲区内容转换为字符串
return out.toString("utf-8");
} finally {
closeQuietly(gzip);
closeQuietly(in);
closeQuietly(out);
}
}
测试用例部分关键代码参考如下:

1.对 UTF8 编码的字符串数据进行压缩,然后存到数据库中

String str = "{"name":"jerome","familyName":"peng","company":"enmotech"}";

System.out.println("input:"+str);

String compress_java = GZipUtils.compress(str);

    try{
ps = conn.prepareStatement(sql);
ps.setInt(1, 100);
ps.setString(2, str);
ps.setString(3, compress_java);
ps.execute();
    } catch (Exception e) {
        e.printStackTrace();
    }

2.从数据库中取出字段进行解密

    sql = " select info,info2 from test where id=100";
    ResultSet rs = null;
    try{
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
    while (rs.next()) {
	String compress_db = rs.getString(2);
        String unCompress= GZipUtils2.unCompress(compress_db );
        System.out.println("output:"+unCompress);
    }
    } catch (Exception e) {
        e.printStackTrace();
    }

期望结果是从数据库中取出来的字符串能够解压出原始数据。也就是上面的 unCompress 变量输出的结果应该要与上面的 str 变量输出结果一致,应为:

{"name":"jerome","familyName":"peng","company":"enmotech"}
如果我们在 pg 数据库里进行测试,上面测试第一步会报错提示无法对 0 字节进行存储

org.postgresql.util.PSQLException: ERROR: invalid byte sequence for encoding "UTF8": 0x00
但在 openGauss/MogDB 里面,数据可以正常存储,不会报错,但是压缩接口进行解码时数据显示乱码。

下面我们对比入库前和入库后的字节序列(以 hex 字符形式显示,两个字符表示一个字节):

入库前的 hex 字符串

1f8b0800000000000000ab56ca4bcc4d55b252ca4a2dca07327494d2127333732afd20a205a979e940b1e4fcdc82c4bc4aa0406a5e6e7e496a7286522d003efb28273a000000
入库后的 hex 字符串

1f8b0820202020202020ab56ca4bcc4d55b252ca4a2dca07327494d2127333732afd20a205a979e940b1e4fcdc82c4bc4aa0406a5e6e7e496a7286522d203efb28273a202020
我们发现其实是 00 与 20 的差异,所有的 hex 00 被转义为了 hex 20,也就是 0 字节被转义为了空格。

既然知道了这个差异,那我们对取出的数据做一次反向替换,应该可以解决这个问题。

我们可以按字节进行读取,如果数值是 32(hex 20 对应十进制 32)的字节,那我们就替换为 0 字节。

if(bytes_src[i]==32) {
bytes_dest[i]=(byte)0;
}else {
bytes_dest[i]=bytes_src[i];
}
这样修改之后测试发现还是有问题,因为压缩后的字节数据里可能也包含 hex 20,这样我们会把不该替换的字节也做了误处理。

进一步修正为只对首尾固定的部分进行处理,思路来源与 GZIP 公共类。

//头部10个字节或者尾部8个字节还原0字节
if((i<=10 || i>=len-1-8) && bytes_src[i]==32) {
bytes_dest[i]=(byte)0;
}else {
bytes_dest[i]=bytes_src[i];
}
这样处理后,测试数据可以正常解压,测试结果如下:

input:{"name":"jerome","familyName":"peng","company":"enmotech"}
HEX_ja:1f8b0800000000000000ab56ca4bcc4d55b252ca4a2dca07327494d2127333732afd20a205a979e940b1e4fcdc82c4bc4aa0406a5e6e7e496a7286522d003efb28273a000000
HEX_db:1f8b0820202020202020ab56ca4bcc4d55b252ca4a2dca07327494d2127333732afd20a205a979e940b1e4fcdc82c4bc4aa0406a5e6e7e496a7286522d203efb28273a202020
HEX_cv:1f8b0800000000000000ab56ca4bcc4d55b252ca4a2dca07327494d2127333732afd20a205a979e940b1e4fcdc82c4bc4aa0406a5e6e7e496a7286522d003efb28273a000000
output:{"name":"jerome","familyName":"peng","company":"enmotech"}

标签:ps,字节,hex,MogDB,bytes,str,openGauss,String
From: https://www.cnblogs.com/helloopenGauss/p/18121360

相关文章

  • openGauss系统函数添加指导
    openGauss系统函数添加指导1、函数架构简介openGauss内函数的可以分为两个部分:​身份注册声明:openGauss中存在一个系统表pg_proc,这个表存放了所有函数的基本元信息,相当于函数的“户口本”,只有在其中可以查到的函数,才可以在SQL语句中进行调用,才有“数据库函数”的身份。......
  • openGauss数据库源码解析——慢SQL检测
    openGauss数据库源码解析——慢SQL检测慢SQL检测的定义:基于历史SQL语句信息进行模型训练,并用训练好的模型进行SQL语句的预测,利用预测结果判断该SQL语句是否是潜在的慢SQL。当发现潜在的慢SQL后,开发者便可以进行针对性优化或者风险评估,以防业务上线后发生问题。慢......
  • openGauss单机部署
    openGauss单机部署一、安装环境操作系统:虚拟机VMware、CentOS7.9环境设置:(1)虚拟机内存3G、磁盘100G(2)系统版本修改一开始使用了centos8,无法安装,因此降低版本,选用7.9后依然存在一些问题,因此修改/etc/redhat-release文件中系统版本为CentOSLinuxrelease7.6(Core)(3)......
  • openGauss内存引擎中的索引
    一、索引索引是一种用于快速查询和检索数据的数据结构。常见的索引结构有:B树,B+树和Hash。索引的作用就相当于目录的作用。打个比方:我们在查字典的时候,如果没有目录,那我们就只能一页一页的去找我们需要查的那个字,速度很慢。如果有目录了,我们只需要先去目录里查找字的位置,......
  • 国产开源数据库OpenGauss的安装运行
    步骤一:OpenGauss的安装环境OS:openEuler20.0364bitwithARM架构:arm64部署:单机安装过程1、环境配置安装依赖包:yuminstalllibaio-develflexbisonncurses-develglibc-develpatchreadline-devel2、创建xml配置文件创建cluster_config.xml配置文件并进行配置......
  • openGauss学习笔记-257 openGauss性能调优-使用Plan Hint进行调优-Custom Plan和Gener
    文章目录openGauss学习笔记-257openGauss性能调优-使用PlanHint进行调优-CustomPlan和GenericPlan选择的Hint257.1功能描述257.2语法格式257.3示例openGauss学习笔记-257openGauss性能调优-使用PlanHint进行调优-CustomPlan和GenericPlan选择的Hint257.......
  • 字节笔试
    1.实现一个返回Promise的异步函数,能够在1000毫秒后向调用方返回字符串"OK"functionpromiseDemo(){returnnewPromise((resolve)=>{setTimeout(()=>{resolve('OK')},1000)})}promiseDemo().then((res)=>{cons......
  • 字节扣子AI:开启全民AI Bot开发新时代
    字节扣子AI(Coze)是由字节跳动推出的新一代一站式AIBot开发平台。该平台旨在为用户提供一个低门槛、快速搭建基于AI模型的各类问答Bot的环境。无论用户是否具备编程基础,都可以在扣子平台上通过简单的操作创建出能够解决简单问答或处理复杂逻辑对话的AI机器人。这不仅为开发者提供了......
  • 中文GPTS,字节中文扣子Coze使用全教程
    字节出自己的GPTS了,名字英文名叫coze,中文名叫“扣子”。和OpenAI的GPTS类似。具有可定制性和完成特定任务的强大功能,它提供了一种新的GPT方式,可以让用户根据自己的需求定制化,并与其他用户共享。 国内用的是云雀大模型。国外目前可以白嫖GPT4。 我体验了一下,并在抖音上测试发......
  • 中文GPTS详尽教程,字节扣子Coze插件使用全输出
    今天,斜杠君和大家分享如何在字节扣子Coze中创建插件,并在创建后如何使用这个插件。 一、新建插件首先,进入到插件页面,创建一个插件。https://www.coze.cn/home 点击左侧的个人空间。 在上面选择”插件“标签,来到插件的页面。点击”创建插件“按钮,开始创建。  在弹......