invalid byte sequence for encoding "UTF8": 0x00(注意:若不是0x00则极可能是字符集设置有误),是PostgreSQL独有的错误信息,直接缘由是varchar型的字段或变量不接受含有'\0'(也即数值0x00、UTF编码'\u0000')的字符串 。官方给出的解决方法:事先去掉字符串中的'\0',例如在Java代码中使用str.replaceAll('\u0000', ''),貌似这是目前惟一可行的方法。sql
几天前,项目的一个程序就出现这种错误,该程序是将一批特殊格式的文件导入到数据库的若干张表中。虽然已知道用replaceAll('\u0000', '')可解决问题,但因为要插入多张表、每一个表含多个varchar字段、插入操做由JPA实现、插入操做要批量进行等因素,程序日志内容太笼统,为判断是哪一个(或哪些)表、字段形成的、以及是代码缘由仍是数据缘由提供的帮助不多,于是过程当中麻烦多多困难重重,如今将其中的经验与教训总结出来,但愿对同行们有所帮助。数据库
一开始用普通方法,即经过在应用程序代码里加断点来跟踪执行状况,但在本例中,一旦跟踪到JPA持久化时就没法继续下去。而因为数据内容不少,用人工一一去检查费时费力,于是走了不少弯路。浏览器
后来,经过修改PostgreSQL配置文件,在运行日志(不是WAL和提交日志)中输出SQL语句执行状况,能够准肯定位到哪一个表会引起错误。具体方法是:函数
原本到这阶段已经至关接近成功了,但仍是在此犯了错误:过于依赖页面所显示的内容,实在是不该该。由于浏览器、某些图形化工具在处理含有'\0'的字符串时会自动截断'\0'后面的内容,依旧没法肯定是表里的哪一个字段。工具
后来,干脆使用古老而经典的方法:在程序日志中按字节内容输出字符串变量(最好加上其长度),很快就准确找到了引起错误的字段。post
同时,代码缘由仍是数据缘由也随之肯定。在本例中,特殊格式的数据文件是由一个早期版本的C程序生成的,极可能因为字符串初始化不完全,生成的部分字段内容在正确内容后附加了一个'\0'和少量乱码,从而引起此次事件。编码
若是按照官方的推荐作法而直接对嫌疑字符串使用str.replaceAll('\u0000', ''),虽然避免了错误发生,以后的乱码却会存入数据库并最终显示在页面。经与客户沟通,确认'\0'以后均为乱码,因而在程序代码中将全部的嫌疑字段的'\0'及乱码一块儿截断:日志
str.trim().split('\u0000')[0];
至此,此次折磨人多日的事件终于获得解决。postgresql
PS:该程序之前在Oracle环境没出现问题,由于Oracle可接受中间带'\0'的字符串进行存储,并在各类界面显示内容时会自动截断后面的内容,于是查不出缘由,只有经过length()函数查询字符串长度才能发现不一致之处。code