分享
 
 
 

JDBC与字符集总结

王朝java/jsp·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

JDBC与字符集总结

danci.z(小谢), 2003.11.16

通过JDBC访问数据库时遇到的字符集问题中,可以归纳为如下因素:

- JVM对字符集的处理

JVM核心完全使用Unicode字符集,编码上采用UTF-16LE(x86和Unix)。 Java编译器扫描.java源文件时将完成预转换,比如在中文Windows上编译.java文件时,你可能已经注意到.java文件中的字符串和.class中的不一样。因为.java文件本身用的是gb2312编码,而.class内则是UTF-16LE编码。如果你的编辑器支持,你可能会选择直接用UTF-8来书写.java源程序,这时Java编译器就会用UTF-8对源程序解码。

在输出时,比如调用System.out.print方法也将完成一个编码转换,在上述情况中经常是将内存中的UTF-16LE编码的字串转换成控制台上可读的gb2312编码。

- JSP页面使用的字符集

运行JSP页面前总会被预处理至.java程序并被编译成.class,注意到JSP总是一个servlet,因此实际上这里存在两个字符集,一是.jsp文件本身使用的字符集,另一则是servlet输出内容的字符集(content-type)。尽量使.jsp文件本身的字符集和输出内容的字符集保持一致,比如一致采用UTF-8。Response的实现将jvm中的UTF-16LE字串转换至<%@page encoding=...%>所指定的编码,

- Connection 使用的字符集

连接的字符集限制了SQL语句可以使用的字符。这在UTF-16中格外明显,如果连接不使用UTF-16的字符集,那么由于大多数的Latin-1字符集对'\0'的处理将使大多数SQL语句成为无效语句,比如SELECT语句通过UTF-16LE编码后将变成"S\0E\0L\0E\0C\0T\0...",服务器的SQL分析器在遇到第一个'\0'便认为语句已经结束。

但仍然可以将UTF-16LE编码的字串送入Latin-1字符集的连接,方法是SQL语句本身仍采用Latin-1编码,而相关的字串(引号内部的)采用UTF-16LE。这种情况下,UTF-16LE的字串不能包括Unicode字符集中编码小于256的字符(包括拉丁字母和数字、英文符号),否则SQL分析器会报告"字符串未结束"之类的错误。(为什么?)

- 数据库系统

并不是所有数据库都支持Unicode,你可能有必要通过字符集转换来保存一些特殊的字符数据。如果数据库仅支持Latin-1字符集(这样的系统不在少数),对于中文的情况,你可以将字符串用Latin-1编码,然后用gb2312解码,觉得困惑?如果你(曾经)是C++程序员,那么这里的编码类似于dynamic_cast, 而解码则相当于reinterpret_cast。

sql_str = new String( java_str.getBytes("ISO-8859-1"), "gb2312" );

在获取数据的时候则刚好相反:

java_str = new String( sql_str.getBytes("gb2312"), "ISO-8859-1" );

如果数据库系统支持Unicode,那么请尽量采用Unicode。有些手册上建议你根据具体情况决定是否使用Unicode,因为Unicode将占用更多的存储空间,而且如果采用UTF-8,排序的速度将会"减慢30% (mysql)",请不要为这些词语而顾虑,大多数情况这些都不是问题。

对于SQL Server 2000,这篇文章值得一读:

http://www.microsoft.com/china/msdn/library/techart/IntlFeaturesInSQLServer2000.asp

最关键的就是你需要在字符串左边加上N字符(N一定要大写),如

INSERT INTO table(name_en, name_native) VALUES('yokohama', N' 横浜 ')

对于Sybase数据库(Sybase 11.5, Sybase 12),系统不支持UTF-16,但支持UTF-8,为了使用Unicode,你可能需要下面的连接字串:

jdbc:sybase:Tds:127.0.0.1:4000/database?charset=utf8&jconnect_version=0

类似的,在SQL语句中使用字符N修饰的字串,使SQL分析器认为字串是Unicode编码的。

对于MySQL数据库,系统支持四个级别的字符集设置:

连接,数据库,表,字段

MySQL参考手册第9章有详细的讨论,但注意版本要求4.1.0以上,同时Windows (nt,2k,xp) 的用户请注意 4.1.0 有个bug,你必须使用4.1.1才能正确使用Unicode。

在 SQL Server 和 Sybase 中都有N开头的字段类型,它们被设计用于国际化的字符存储。在SQL Server中,比如NTEXT实际上就是用Unicode存储的的字段类型。

SQL-99规定了Unicode字符串统一使用 u 前缀,如 u"コンピュータ",但目前还没有见哪个数据库系统支持这种语法。

附:几个字符集支持的测试例子 (需要测试用的源码可以向我要:jljljjl@yahoo.com

声明:

Connection c;

Statement s;

生成数据:

String lit1 = "的文本:中华人民共和国]";

String[] encs = new String[] {

"(default)",

"ISO-8859-1",

"cp850",

"gb2312",

"gbk",

"big5",

"UTF-16LE",

"UTF-16BE",

"UTF-8",

};

String javaSrc = "[这是默认编码" + lit1;

byte[] rawdata;

s.executeUpdate("DELETE FROM StringTable");

for (int i = 0; i < encs.length; i++) {

String targetEncoding = encs[i];

javaSrc = "[这是" + targetEncoding + lit1;

String testTarget;

if (i == 0) {

rawdata = javaSrc.getBytes();

testTarget = new String(rawdata);

} else {

rawdata = javaSrc.getBytes(targetEncoding);

testTarget = new String(rawdata);

}

System.out.println(testTarget);

String sql = ("INSERT INTO StringTable(charset,text) VALUES(" +

"'" + targetEncoding + "', N'" + testTarget + "')");

System.out.println(sql);

s.executeUpdate(sql);

}

获取数据:

ResultSet rs = s.executeQuery("SELECT * FROM StringTable");

String charset;

String text;

while (rs.next()) {

charset = rs.getString("charset").trim();

text = rs.getString("text");

System.out.println(charset + ": [" + text + "]");

byte[] raws = text.getBytes();

String restore;

if ("(default)".equals(charset)) {

restore = new String(raws);

} else {

restore = new String(raws, charset);

}

System.out.println(" --> [" + restore + "]");

}

典型测试结果:

SQL-Server, type = ntext

(default): [[这是(default)的文本:中华人民共和国]]

--> [[这是(default)的文本:中华人民共和国]]

ISO-8859-1: [[??ISO-8859-1???????????]]

--> [[??ISO-8859-1???????????]]

cp850: [[??cp850???????????]]

--> [[??cp850???????????]]

gb2312: [[这是gb2312的文本:中华人民共和国]]

--> [[这是gb2312的文本:中华人民共和国]]

gbk: [[这是gbk的文本:中华人民共和国]]

--> [[这是gbk的文本:中华人民共和国]]

big5: [[?琌big5ゅセい?チ㎝?]]

--> [[?是big5的文本:中?人民共和?]]

UTF-8: [[杩欐槸UTF-8鐨勬枃鏈細涓崕浜烘皯鍏卞拰鍥絔]

--> [[这是UTF-8的文本:中华人民共和国]]

SQL-Server, type = text

(default): [[这是(default)的文本:中华人民共和国]]

--> [[这是(default)的文本:中华人民共和国]]

ISO-8859-1: [[??ISO-8859-1???????????]]

--> [[??ISO-8859-1???????????]]

cp850: [[??cp850???????????]]

--> [[??cp850???????????]]

gb2312: [[这是gb2312的文本:中华人民共和国]]

--> [[这是gb2312的文本:中华人民共和国]]

gbk: [[这是gbk的文本:中华人民共和国]]

--> [[这是gbk的文本:中华人民共和国]]

big5: [[?琌big5ゅセい?チ㎝?]]

--> [[?是big5的文本:中?三民囝和?]]

UTF-8: [[杩欐槸UTF-8鐨勬枃鏈細涓崕浜烘皯鍏卞拰鍥絔]

--> [[这是UTF-8的文本:中华人民共和国]]

Sybase, type = char

(default): [[??(default)???????????]]

--> [[??(default)???????????]]

ISO-8859-1: [[??ISO-8859-1???????????]]

--> [[??ISO-8859-1???????????]]

cp850: [[??cp850???????????]]

--> [[??cp850???????????]]

gb2312: [[??gb2312???????????]]

--> [[??gb2312???????????]]

gbk: [[??gbk???????????]]

--> [[??gbk???????????]]

big5: [[??big5???????????]]

--> [[??big5???????????]]

UTF-16LE

--> [[?啦吀??????????乎?民共?]]

UTF-16BE:

--> [[??唀吀??????????乎?共吿??]

UTF-8: [[???UTF-8?????????????????]

--> [[???UTF-8?????????????????]

Sybase, type = nchar

(default): [[??(default)???????????]]

--> [[??(default)???????????]]

ISO-8859-1: [[??ISO-8859-1???????????]]

--> [[??ISO-8859-1???????????]]

cp850: [[??cp850???????????]]

--> [[??cp850???????????]]

gb2312: [[??gb2312???????????]]

--> [[??gb2312???????????]]

gbk: [[??gbk???????????]]

--> [[??gbk???????????]]

big5: [[??big5???????????]]

--> [[??big5???????????]]

UTF-16LE

--> [[?啦吀??????????乎?民共?]]

UTF-16BE:

--> [[??唀吀??????????乎?共吿??]

UTF-8: [[???UTF-8?????????????????]

--> [[???UTF-8?????????????????]

Sybase, type = char, charset=utf8

(default): [[这是(default)的文本:中华人民共和国]]

--> [[这是(default)的文本:中华人民共和国]]

ISO-8859-1: [[??ISO-8859-1???????????]]

--> [[??ISO-8859-1???????????]]

cp850: [[??cp850???????????]]

--> [[??cp850???????????]]

gb2312: [[这是gb2312的文本:中华人民共和国]]

--> [[这是gb2312的文本:中华人民共和国]]

gbk: [[这是gbk的文本:中华人民共和国]]

--> [[这是gbk的文本:中华人民共和国]]

big5: [[?琌big5ゅセい?チ㎝?]]

--> [[?是big5的文本:中?人民共和?]]

UTF-16LE: [[这是UTF-16LE的文本?中华人民共和国]]

UTF-16BE: [[这是UTF-16BE的文本?中华人民共和嘿]]

UTF-8: [[杩欐槸UTF-8鐨勬枃鏈細涓崕浜烘皯鍏卞拰鍥絔]

--> [[这是UTF-8的文本:中华人民共和国]]

Sybase, type = nchar, charset=utf8

(default): [[这是(default)的文本:中华人民共和国]]

--> [[这是(default)的文本:中华人民共和国]]

ISO-8859-1: [[??ISO-8859-1???????????]]

--> [[??ISO-8859-1???????????]]

cp850: [[??cp850???????????]]

--> [[??cp850???????????]]

gb2312: [[这是gb2312的文本:中华人民共和国]]

--> [[这是gb2312的文本:中华人民共和国]]

gbk: [[这是gbk的文本:中华人民共和国]]

--> [[这是gbk的文本:中华人民共和国]]

big5: [[?琌big5ゅセい?チ㎝?]]

--> [[?是big5的文本:中?人民共和?]]

UTF-16LE: --> [[这是UTF-16LE的文本?中华人民共和国]]

UTF-16BE: --> [[这是UTF-16BE的文本?中华人民共和嘿]]

UTF-8: [[杩欐槸UTF-8鐨勬枃鏈細涓崕浜烘皯鍏卞拰鍥絔]

--> [[这是UTF-8的文本:中华人民共和国]]

Sybase, type = char, charset=cp936

(default): [[这是(default)的文本:中华人民共和国]]

--> [[这是(default)的文本:中华人民共和国]]

ISO-8859-1: [[??ISO-8859-1???????????]]

--> [[??ISO-8859-1???????????]]

cp850: [[??cp850???????????]]

--> [[??cp850???????????]]

gb2312: [[这是gb2312的文本:中华人民共和国]]

--> [[这是gb2312的文本:中华人民共和国]]

gbk: [[这是gbk的文本:中华人民共和国]]

--> [[这是gbk的文本:中华人民共和国]]

big5: [[?琌big5ゅセい?チ㎝?]]

--> [[?是big5的文本:中?人民共和?]]

UTF-16LE: --> [[这是UTF-16LE的文本?中华人民共和国]]

UTF-16BE: --> [[这是UTF-16BE的文本?中华人民共和嘿]]

UTF-8: [[杩欐槸UTF-8鐨勬枃鏈細涓崕浜烘皯鍏卞拰鍥絔]

--> [[这是UTF-8的文本:中华人民共和国]]

Sybase, type = char, charset=eucgb

(default): [[这是(default)的文本:中华人民共和国]]

--> [[这是(default)的文本:中华人民共和国]]

ISO-8859-1: [[??ISO-8859-1???????????]]

--> [[??ISO-8859-1???????????]]

cp850: [[??cp850???????????]]

--> [[??cp850???????????]]

gb2312: [[这是gb2312的文本:中华人民共和国]]

--> [[这是gb2312的文本:中华人民共和国]]

gbk: [[这是gbk的文本:中华人民共和国]]

--> [[这是gbk的文本:中华人民共和国]]

big5: [[??big5?ゅセ?い??チ???]]

--> [[??big5?文本?中??民???]]

UTF-16LE: --> [[?啦吀??????????乎?民共?]]

UTF-16BE: --> [[??唀吀??????????乎?共吿??]

UTF-8: [[杩??UTF-8??????涓??浜烘??卞???]

--> [[???UTF-8?????????人????????]

Sybase, type = nchar, charset=eucgb

(default): [[这是(default)的文本:中华人民共和国]]

--> [[这是(default)的文本:中华人民共和国]]

ISO-8859-1: [[??ISO-8859-1???????????]]

--> [[??ISO-8859-1???????????]]

cp850: [[??cp850???????????]]

--> [[??cp850???????????]]

gb2312: [[这是gb2312的文本:中华人民共和国]]

--> [[这是gb2312的文本:中华人民共和国]]

gbk: [[这是gbk的文本:中华人民共和国]]

--> [[这是gbk的文本:中华人民共和国]]

big5: [[??big5?ゅセ?い??チ???]]

--> [[??big5?文本?中??民???]]

UTF-16LE: --> [[?啦吀??????????乎?民共?]]

UTF-16BE: --> [[??唀吀??????????乎?共吿??]

UTF-8: [[杩??UTF-8??????涓??浜烘??卞???]

--> [[???UTF-8?????????人????????]

(从以上测试中可以看出,我的.java文件是用gb2312编码的。)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有