openGauss/MogDB零字节问题处理
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"}
openGauss/MogDB零字节问题处理的更多相关文章
- C语言中的位操作(12)--判断一个数字是否包含一个全零字节
本文主要介绍一系列算法,算法主要功能是判断一个数字(二进制)中是否包含全零字节 e.g.1010 1111 0000 0000 1001 1111 0001 1111 即 32位整数:A4A3A2A1 ...
- 各种编码中汉字所占字节数;中文字符集编码Unicode ,gb2312 , cp936 ,GBK,GB18030
vim settings set fileencodings=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936,latin1set termencoding=utf-8se ...
- BOM的来源是不可能出现的字符,GB2312双字节高位都是1,Unicode理论的根本缺陷导致UTF8的诞生
Unicode字符编码规范 http://www.aoxiang.org 2006-4-2 10:48:02Unicode是一种字符编码规范 . 先从ASCII说起.ASCII是用来表示英文字符的 ...
- 【实验向】问题:假设计算机A和计算机B通信,计算机A给计算机B发送一串16个字节的二进制字节串,以数组形式表示:
问题: 假设计算机A和计算机B通信,计算机A给计算机B发送一串16个字节的二进制字节串,以数组形式表示: unsigned char[16] = {0x3f, 0xa0, 0x00, 0x00, 0x ...
- oracle to mogdb 迁移---mtk工具
## 一.MTK工具介绍--------- MTK–异构数据迁移工具 MTK全称为 Database Migration Toolkit,是一个可以将Oracle/DB2/MySQL/openGaus ...
- 前端学HTTP之实体和编码
前面的话 每天都有各种媒体对象经由HTTP传送,如图像.文本.影片以及软件程序等.HTTP要确保它的报文被正确传送,识别.提取以及适当处理.为了实现这些目标,HTTP使用了完善的标签来描述承载内容的实 ...
- Linux设备文件简介(转载)
Linux 中的设备有2种类型:字符设备(无缓冲且只能顺序存取).块设备(有缓冲且可以随机存取).每个字符设备和块设备都必须有主.次设备号,主设备号相同的设 备是同类设备(使用同一个驱动程序).这些设 ...
- 我的MYSQL学习心得(四) 数据类型
我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(五) 运 ...
- PHP curl报错“Problem (2) in the Chunked-Encoded data”解决方案
$s = curl_init(); curl_setopt($s, CURLOPT_POST, true); curl_setopt($s, CURLOPT_POSTFIELDS, $queryStr ...
- [转]C语言SOCKET编程指南
1.介绍 Socket编程让你沮丧吗?从man pages中很难得到有用的信息吗?你想跟上时代去编Internet相关的程序,但是为你在调用 connect() 前的bind() 的结构而不知所措?等 ...
随机推荐
- nftables语法及例子
先上我自己实际测试通过的例子,用例子便于在实践中学习: # 0 --- 说明 ---下面例子中的单引号目的是为了避免nftable参数中的星号.花括号.分号等符号被shell展开解释掉了,导致nft命 ...
- nginx应用及性能调优
1. Nginx 反向代理实现 说反向代理之前 先说什么是正向代理, 正向代理是指客户端通过 代理服务器访问目标服务器,客户端直接访问代理服务器,在由代理服务器访问目标服务器并返回客户端并返回 . 例 ...
- iview 表单验证 爆红后,有某些组件现隐,爆红和必填会错位,解决方案 组件上加key
iview 表单验证 爆红后,有某些组件现隐,爆红和必填会错位,解决方案 组件上加key
- iview 日期组件 清空后验证没报红,需要在onChange 进行单独 validateField,因为空字符串校验没有触发
// 日期组件的 onChange this.yourObj.xxxTime = item this.$refs.yourForm.validateField('xxxTime')
- Java线上诊断神器Arthas:常用命令详解!
有关Arthas基本介绍.安装部署.arthas idea插件在上篇文章已经介绍过,这里就不在重述. 文章地址:Java诊断工具Arthas:开篇之watch实战 上篇重点讲了 watch 命令.这篇 ...
- 菜鸟角度简单分析BP算法(Error Back Propagation)
PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明 本文作为本人csdn blog的主站的备份.(Bl ...
- Linux安装jdk和mysql
Linux安装jdk和mysql JDK安装 操作步骤: 使用FinalShell自带的上传工具将jdk的二进制发布包上传到Linux空jdk-8u171-inux-x64.tar.gz(这里注意自己 ...
- 记录--怎么实现一个3d翻书效果
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 本篇主要讨论以下两种翻书动画的实现: 第一种是整页翻转的效果: 这种整页翻转的效果主要是做rotateY的动画,并结合一些CSS的3d属性 ...
- linux查看资源使用情况
linux查看资源使用情况 top -c # 查看资源使用情况 top 输出如下内容 top - 14:54:21 up 95 days, 20:03, 3 users, load average: ...
- 为什么SOTA网络在你的数据集上不行?来看看Imagnet结果的迁移能力研究
论文通过实验证明,ImageNet上的模型并不总能泛化到其他数据集中,甚至可能是相反的,而模型的深度和宽度也会影响迁移的效果. 如果需要参考,可选择类别数与当前任务相似的数据集上的模型性能.论文通 ...