2023年8月1日发(作者:)

为什么汉字会显⽰为?号?今天遇到⼀个问题,从teradata数据库,⽤java读取汉字的时候,如果是⽣僻字,就读不出来,显⽰为乱码和问号。刚开始以为是客户端字体的问题,但是调整了半天,也没有什么⽤。后来以为是客户端解码的问题,尝试将gbk转换成utf-8,也没有解决问题。后来只好将数据表的字段改为unicode编码,才解决了问题。但是,仍然觉得这样的解决⽅案实在不够完美,对于数据库、jdbc、客户端之间的数据传输机制并没有理清楚。思考了⼀下,从根本原理上来梳理数据库、jdbc、java客户端三者关系,终于搞明⽩了。在理解这个关系之前,要有⼀点关于汉字编码的基础知识。汉字的数量很多,包括常⽤字和⽣僻字。其中常⽤字,以前使⽤gb2312字符集来表⽰;⽣僻的汉字在gb2312⾥是没有登记的,这些汉字被收录到gbk字符集了。有了这个基础知识,后⾯的分析就好理解了 。⾸先,数据库负责如实的记录客户打算存储的数据。如果客户将字段A的字符集设置为ascii,然后往这个字段⾥存⼊了汉字,⽽且是⽣僻的汉字。假如你使⽤某种⼯具,能够正常显⽰数据表中的⽣僻汉字,这就说明,这些汉字采⽤了gbk编码。(我⽤teradata sql assistant的确可以查出数据库中的⽣僻汉字,⽽且显⽰正常)其次,如果我们⽤jdbc driver去读数据库,发⽣了什么事情呢?在连接数据库的时候,jdbc url⾥要写清楚,本次连接数据库,打算按什么字符集去解释数据库中的内容。像以上情况,数据库按ascii存放中⽂,那么jdbcurl⾥就要按charset=ascii去写,否则肯定就不⼀致。其三,jdbc driver帮忙把数据从数据库⾥读出之后,还会重新组装成java string给程序,⽅便程序处理。问题其实出在这⾥。因为这⾥的组装,我们是不清楚的,是jdbc⾃⼰处理的,是个⿊箱。但是我们可以猜⼀下。如果⽣僻字在数据库存储正常,⽤专⽤客户端查询显⽰正常,⽤jdbcdriver连接后查询,显⽰为”?”。很⼤的可能就是⽣僻字在数据库端采⽤gbk编码,到了客户端,按gb2312编码进⾏映射,结果⽣僻字映射不到,就会显⽰为”?”其四,观察了⼀下jdbcurl的构成,其中果然有⼀个client_charset的属性被设置了,设置值为euc_CN。经查询,这个就是gb2312的另外⼀个名字。如果把euc_CN改为gbk,问题就解决了。⽣僻汉字被正确映射了,使⽤jdbc也能正确查询⽣僻汉字了。

2023年8月1日发(作者:)

为什么汉字会显⽰为?号?今天遇到⼀个问题,从teradata数据库,⽤java读取汉字的时候,如果是⽣僻字,就读不出来,显⽰为乱码和问号。刚开始以为是客户端字体的问题,但是调整了半天,也没有什么⽤。后来以为是客户端解码的问题,尝试将gbk转换成utf-8,也没有解决问题。后来只好将数据表的字段改为unicode编码,才解决了问题。但是,仍然觉得这样的解决⽅案实在不够完美,对于数据库、jdbc、客户端之间的数据传输机制并没有理清楚。思考了⼀下,从根本原理上来梳理数据库、jdbc、java客户端三者关系,终于搞明⽩了。在理解这个关系之前,要有⼀点关于汉字编码的基础知识。汉字的数量很多,包括常⽤字和⽣僻字。其中常⽤字,以前使⽤gb2312字符集来表⽰;⽣僻的汉字在gb2312⾥是没有登记的,这些汉字被收录到gbk字符集了。有了这个基础知识,后⾯的分析就好理解了 。⾸先,数据库负责如实的记录客户打算存储的数据。如果客户将字段A的字符集设置为ascii,然后往这个字段⾥存⼊了汉字,⽽且是⽣僻的汉字。假如你使⽤某种⼯具,能够正常显⽰数据表中的⽣僻汉字,这就说明,这些汉字采⽤了gbk编码。(我⽤teradata sql assistant的确可以查出数据库中的⽣僻汉字,⽽且显⽰正常)其次,如果我们⽤jdbc driver去读数据库,发⽣了什么事情呢?在连接数据库的时候,jdbc url⾥要写清楚,本次连接数据库,打算按什么字符集去解释数据库中的内容。像以上情况,数据库按ascii存放中⽂,那么jdbcurl⾥就要按charset=ascii去写,否则肯定就不⼀致。其三,jdbc driver帮忙把数据从数据库⾥读出之后,还会重新组装成java string给程序,⽅便程序处理。问题其实出在这⾥。因为这⾥的组装,我们是不清楚的,是jdbc⾃⼰处理的,是个⿊箱。但是我们可以猜⼀下。如果⽣僻字在数据库存储正常,⽤专⽤客户端查询显⽰正常,⽤jdbcdriver连接后查询,显⽰为”?”。很⼤的可能就是⽣僻字在数据库端采⽤gbk编码,到了客户端,按gb2312编码进⾏映射,结果⽣僻字映射不到,就会显⽰为”?”其四,观察了⼀下jdbcurl的构成,其中果然有⼀个client_charset的属性被设置了,设置值为euc_CN。经查询,这个就是gb2312的另外⼀个名字。如果把euc_CN改为gbk,问题就解决了。⽣僻汉字被正确映射了,使⽤jdbc也能正确查询⽣僻汉字了。