JDBC中头文字N类型兼容方法笔记

来源:互联网 发布:spycall软件免费下载 编辑:程序博客网 时间:2024/05/17 05:59

开发JDBC+MS SQL SERVER 相关的内容时,遇到Tomcat 7下UTF-8编码的页面无法正常显示中文文字,而相对地英文字母可以正常显示。如:

Medicine.
medBook
ntext:NullableMedicine.
medNameEN
ntext:Nullable0-NNS,gI?0root of Hemsley cowparsnip而真实的数据应该是medBook=《中华本草》 medNameEn=root of Hemsley cowparsnip。

实际页面其字节数为0-NNS,gI?0/12root of Hemsley cowparsnip/52

(即事实上英文字每个前都有类似0x00之类的不可见字符)

根据各种测试,基本得出问题所在:

首先,出现乱码的数据类型为NVARCHAR,使用Unicode编码存储;

我所使用的JDBC尚未实现getNString(int) 方法,这也就意味着在JDBC的读取数据流中,并不能按照nvarchar的方式双字节读取,反而是将一个字拆分为两个单独的字节处理;

SQL SERVER 2008中的编码方式应该是默认的ANSI/GBK。

以上,基本得出上述乱码的来源为N字开头的类型的数据之每一个字都被拆成了2个字节,每个字节在JDBC中转码为JAVA内部使用的Unicode,之后再以对应的字母(基本就是ASCII码)的形式显示出来。


理论上分析的结论是很明显的,可以通过逆转换推出原数据。然而实际上还未成功实现。


相对而言,拿自己之前写过的通用C#SQL查询程序对同一数据库进行连接之后,明显,C#对N字类型的支持要远远好于JAVA,即几乎不需要人工干预,当然这得益于C#的字符类型实现。


//sleep(several_hours);


醒来之后继续研究,这回决定从点到面,先把上述乱码的文字编码全部解析一遍,结果如下:

UnicodeUTF-8GBKCHARraw300Ae3 80 8aa1 b6《0a 304E2De4 b8 add6 d0中2d 4e534Ee5 8d 8ebb aa华4e 53672Ce6 9c acb1 be本2c 678349e8 8d 89b2 dd草48 -125(ffffff83)300Be3 80 8ba1 b7》0b 30就直接观察而言,raw code和Unicode码基本是高低字节位置互换了。于是先尝试将每个接受到的(raw string中的)字符转换为高低字节互换的结果。于是其中涉及到大于0x7f的字节就会有符号问题。这一问题可以通过不直接接收String而是用接受Bytes来改进。


附,NetBeans 7+jdk7下的解析结果

run:
《中华本草》
got rei codes(6):300a 4e2d 534e 672c 8349 300b 
got raw codes(12):a 30 2d 4e 4e 53 2c 67 49 3f b 30 
got uni codes(12):30 a 4e 2d 53 4e 67 2c 3f 49 30 b 
《中华本㽉》
Using bytes!
got raw codes(12):a 30 2d 4e 4e 53 2c 67 49 ffffff83 b 30 
got uni codes(12):30 a 4e 2d 53 4e 67 2c ffffff83 49 30 b 
《中华本草》
成功生成(总时间:1 秒)


包含英文字母的中文内容实例:

public static void main(String[] argv) throws SQLException, UnsupportedEncodingException {               ResultSet rs = DBQuery("select medEnvironment from Medicine where medId=58");        boolean hasfirst = rs.first();               System.out.println("Using bytes!");        if (hasfirst) {            byte[] bytes = rs.getBytes(1);            byte[] nbytes=new byte[bytes.length];            System.out.print("got raw codes(" + bytes.length + "):");            for (byte b : bytes) {                System.out.print(Integer.toHexString((int) b) + " ");            }            System.out.println();            System.out.print("got uni codes("+bytes.length+"):");            for (int i = 0; i < bytes.length; i += 2) {                nbytes[i] = bytes[i+1];                nbytes[i + 1] =bytes[i];                System.out.print(Integer.toHexString(nbytes[i]) + " " + Integer.toHexString(nbytes[i + 1]) + " ");            }            System.out.println();            String newUnicode = new String(nbytes, "Unicode");            System.out.println(newUnicode);                    }    }
运行结果为:

run:
Using bytes!
got raw codes(116):1f 75 1 60 ffffffaf 73 ffffff83 58 1a ffffffff 1f 75 ffffff8e 4e 77 6d ffffffd4 62 31 0 30 0 30 0 30 0 6d 0 ffffffe5 4e b 4e ffffff84 76 37 ffffff8c 1 30 53 ffffff90 ffffffef ffffff8d ffffffc1 65 1 30 34 6c ffffff9f 6c ffffffb9 ffffff8f 16 62 ffffff97 67 2d 4e 6e 6f 7f 6e 30 57 2 30 44 ffffff8d ffffff90 6e 6 52 3 5e 1a ffffffff 6 52 3 5e ffffff8e 4e 59 6d 5f 6c 1 30 5f 6c 7f ffffff89 1 30 ffffff8f 79 fffffffa 5e 1 30 56 6e 57 53 1 30 7f 5e 1c 4e 49 7b 30 57 2 30 
got uni codes(116):75 1f 60 1 73 ffffffaf 58 ffffff83 ffffffff 1a 75 1f 4e ffffff8e 6d 77 62 ffffffd4 0 31 0 30 0 30 0 30 0 6d 4e ffffffe5 4e b 76 ffffff84 ffffff8c 37 30 1 ffffff90 53 ffffff8d ffffffef 65 ffffffc1 30 1 6c 34 6c ffffff9f ffffff8f ffffffb9 62 16 67 ffffff97 4e 2d 6f 6e 6e 7f 57 30 30 2 ffffff8d 44 6e ffffff90 52 6 5e 3 ffffffff 1a 52 6 5e 3 4e ffffff8e 6d 59 6c 5f 30 1 6c 5f ffffff89 7f 30 1 79 ffffff8f 5e fffffffa 30 1 6e 56 53 57 30 1 5e 7f 4e 1c 7b 49 57 30 30 2 
生态环境:生于海拔1000m以下的谷、道路旁、水沟边或林中潮湿地。资源分布:分布于浙江、江西、福建、湖南、广东等地。
成功生成(总时间:1 秒)