[转] SqlServe到PG迁移错误:无效的编码序列"UTF8": 0x00

简介:

标签

PostgreSQL , Greenplum , 0x00 , 空字符 , NUL , 数据清洗 , 规则 , 过滤 , 非法字符


      背景



环境:

sqlserver2008 R2 (winXP)  
  
postgresql9.3.4 (win7-64bit)  

1. 通过java像PostgreSQL提交批量 insert(或者普通insert或者执行copy):

错误:

java.sql.BatchUpdateException: 批次处理 被中止,呼叫 getNextException 以取得原因。

解决:在catch模块打印出getNextException的内容,就能知道具体的原因是什么了。

catch (ClassNotFoundException | SQLException ex)  
{  
       System.out.println("Error: " + ex.getMessage());  
       ex.printStackTrace(System.out);  
       if (ex instanceof BatchUpdateException)  
       {  
             BatchUpdateException bex = (BatchUpdateException) ex;  
             bex.getNextException().printStackTrace(System.out);  
       }  
}  

2. getNextException抓到的具体错误信息是:org.postgresql.util.PSQLException: ERROR: invalid byte sequence for encoding "UTF8": 0x00

org.postgresql.util.PSQLException: ERROR: invalid byte sequence for encoding "UTF8": 0x00  
 at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2198)  
 at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1927)  
 at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:405)  
 at org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch(AbstractJdbc2Statement.java:2892)  
 at JDBCTest.ConnTest.main(ConnTest.java:154)  

3. 经查看sqlsever和PG的字符编码:

sql server的字符集编码是GBK(对于sqlserver查看encoding很复杂,我看参考了这个方法 http://bbs.csdn.net/topics/190034619 )

PostgreSQL的字符集编码是UTF8(对于PG来说很容易查看encoding,看一下属性中的encoding就可以)

这样看来两个数据库的字符集编码不同,但是PG的服务器端不支持字符集GBK,也就是创建数据库时不能指定encoding=GBK,PG中可替代GBK的字符集EUC_CN也无法使用。只有客户端可以支持GBK,但该设置只在一个连接中有效,故在插入数据之前执行 ppstmt =conn.prepareStatement("set client_encoding=GBK;");,此时又产生了如下错误:

org.postgresql.util.PSQLException: The server's client_encoding parameter was changed to GBK. The JDBC driver requires client_encoding to be UTF8 for correct operation.  
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1966)  
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)  
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:561)  
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:419)  
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:365)  
    at JDBCTest.ConnTest.main(ConnTest.java:56)  

这样看来,sqlserver和PG的字符集没法实现完全统一。

4. 重新回到invalid byte sequence for encoding "UTF8": 0x00。

我在postgresql的社区邮件列表里找到了这个问题:http://postgresql.1045698.n5.nabble.com/invalid-byte-sequence-for-encoding-quot-UTF8-quot-0x00-td2172080.html

http://postgresql.1045698.n5.nabble.com/supporting-0x00-from-client-Unicode-JDBC-td1969492.html#a1969493

通过邮件列表中提到的内容以及个人多次测试报错表的字段,发现导致问题的原因就是字符类型字段值中含有空字符,这是一个结束符。(Unicode 查询工具 http://www.scarfboy.com/coding/unicode-tool?s=U%2B2323)。

5. 问题重现:

在sqlserver中:

create table test_varchar3 (id int,name varchar(23));  
insert into test_varchar3  values (1,'ddd'+CHAR(0)+'aaa');  
insert into test_varchar3  values (2,'ddd'+CHAR(0));  
insert into test_varchar3  values (3,CHAR(0)+'aaa');  
insert into test_varchar3  values (4,'aaa'); ---注意此种的仅仅是字符串并不是空字符''  
select * from test_varchar3;  

将该表从sqlserver迁移到pg:

通过jdbc取到的(其中空字符无法表示,此处用空格替代):

id,name,name_length  
  
1,ddd aaa,length=7  
  
2,ddd ,length =4  
  
3, aaa,length=4  
  
4,aaa,length=5  

错误重现:invalid byte sequence for encoding "UTF8": 0x00。

解决方法:在向pg中copy或者insert数据提交之前,现将其中的字符类型字段值中的空字符取掉即可成功执行。

比如:str.replaceAll("", ""); 或者str.replace("", "");

6. 扩展问题:

sqlserver中字符类型字段值,当插入的字符值中带有空字符的时候,sqlserver客户端显示时会去掉空字符之后的字符,但是在查询中要查到该条数据还需要匹配之后的内容:

pic

create table test_varchar3 (id int,name varchar(23));  
insert into test_varchar3  values (1,'ddd'+CHAR(0)+'aaa');  
insert into test_varchar3  values (2,'ddd'+CHAR(0));  
insert into test_varchar3  values (3,CHAR(0)+'aaa');  
insert into test_varchar3  values (4,'aaa');  
select * from test_varchar3;  
select * from test_varchar3 where name='ddd';  
id | name  
-------------  
2  |  ddd  
select * from test_varchar3 where name='ddd'+CHAR(0);  
id | name  
-------------  
2  |  ddd  
select * from test_varchar3 where name='ddd'+CHAR(0)+'aaa';  
id | name  
-------------  
1  |  ddd  
select * from test_varchar3 where name=CHAR(0);  
id | name  
------------  
  
select * from test_varchar3 where name=CHAR(0)+'aaa';  
id | name  
-------------  
3  |     

关于如何从sqlsever数据库中去掉子赋值中的空值结束符,可以参考(待补充):

http://stackoverflow.com/questions/3533320/sql-server-remove-end-string-character-0-from-data

所以说尽管空值终止符''是空的不显示的,但是他会对字符类型字段值及其查询等造成影响,所以使用sqlsever最好不要向字符类型字段中插入带有空值终止符''的字符或字符串。

关于空值终止符''或者其他控制符的详细介绍,请参考MS SQL Server官方文档:

http://msdn.microsoft.com/en-us/library/ms191485.aspx

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍如何基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
存储 分布式计算 资源调度
ARM+麒麟大数据环境搭建:Hadoop
ARM+麒麟大数据环境搭建:Hadoop
3782 0
ARM+麒麟大数据环境搭建:Hadoop
|
SQL 数据库
DBeaver执行sql文件
本文介绍了DBeaver这款支持多种数据库的通用数据库管理工具和SQL客户端,它具备查看数据库结构、执行SQL查询和脚本、浏览和导出数据等功能。
4949 1
DBeaver执行sql文件
|
数据采集 机器学习/深度学习 自然语言处理
智能风险管理的技术架构:2025从数据采集到自主决策的全链路解析
本文系统梳理了项目风险管理的技术演进历程,从文档驱动到智能化阶段,深入解析各时期关键技术与工具架构,并结合实践案例提出前瞻性实施策略,助力项目管理专业人士构建智能风险管理体系。
1113 2
|
Arthas Kubernetes 调度
一次线上Xxl-Job定时任务调度失败的排查与解决
在XXL-JOB系统中,每分钟执行一次的任务出现调度异常:首次调度成功,第二次调度失败,但第三次调度显示的是第二次任务的执行时间。问题源于调度中心发送的心跳请求未得到执行器响应,导致连接被Envoy代理关闭。Envoy在等待心跳响应时,后续调度请求被阻塞,直至连接因超时关闭。调度中心收到503响应后也会关闭连接,从而影响第三次调度。解决方案是更新执行器以处理心跳请求或配置Istio Sidecar以绕过Envoy代理特定流量。
4901 1
|
Java Maven Spring
如何在idea中创建Springboot项目? 手把手带你创建Springboot项目,稳!
文章详细介绍了在IDEA中创建Spring Boot项目的过程,包括选择Spring Initializr、配置项目属性、选择Spring Boot版本、导入依赖、等待依赖下载以及项目结构简介。
23937 1
|
数据采集 JavaScript 前端开发
网页抓取进阶:如何提取复杂网页信息
在信息爆炸时代,从复杂网页中高效抓取数据对开发者和分析师至关重要。本文探讨如何利用 `webpage` 对象结合代理IP技术,轻松抓取如大众点评这类动态加载且具备反爬机制的网站数据。通过 Python 的 `requests`、`BeautifulSoup` 和 `Selenium`,结合代理IP,详细讲解了如何应对动态内容加载、反爬机制等问题,并提供了具体代码实现。通过这种方法,可以批量抓取商家信息,为数据分析提供支持。
1727 1
网页抓取进阶:如何提取复杂网页信息
|
SQL 数据挖掘 大数据
如何在 SQL Server 中使用 `OFFSET` 和 `FETCH`
【8月更文挑战第10天】
4188 8
|
Shell Docker 容器
docker给容器分配固定ip
docker给容器分配固定ip
3134 3
|
Cloud Native Java 物联网
NATS
【7月更文挑战第8天】
676 4

热门文章

最新文章