`

(转)JDBC与字符集总结

    博客分类:
  • jdbc
阅读更多

http://tech.ccidnet.com/art/3737/20051007/472823_1.html

JDBC与字符集总结

发布时间:2006.03.10 07:40      来源:CSDN     作者:

 


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编码的。)

分享到:
评论

相关推荐

    jdbc连接数据库的乱码问题(已解决)

    jdbc连接mysql出现了乱码,总结起来就是里面的四个编码方式是一样的时候,就不会乱码了,简之,客户连接数据库返回结果(编码必须一致)。

    groovy将JDBC中oracle存储过程游标转换为多层json

    入参是字符串格式的xml,目的是解析xml节点值,作为数据库检索where条件,检索出数据库记录,利用四个游标返回四个数据集,然后用groovy脚本将四个游标数据集解析成json出参中对应的四个节点值。出参json有两层结构...

    JAVA笔试面试资料JDBC HTTP、JSP、Servlet、Struts面试题汇总资料.zip

    JAVA笔试面试资料JDBC HTTP...写出正则表达式,从一个字符串中提取链接地址.docx 出现几率最高和覆盖范围最广的一套经典Java面试题.docx 最新Java编程面试题全集(共50道题+答案).docx 遇到的一些Java面试题回顾.docx

    Java重点知识总结

    字符串(常量、与字符常量的区别、连接运算、例2.18) 。。。。。。。 。。。。 第9章 流的概念 字节流的类的作用、类层次 字符流的类的作用、类层次 随机文件存取类作用 第10章 URL、URLConnection类支持的协议 TCP...

    Java语言基础下载

    可滚动的和可更新的结果集 350 批处理更新 354 二进制大对象BLOB 357 RowSet 新特性 359 JdbcRowSet 360 FilteredRowSet 361 内容总结 363 独立实践 364 第二十一章:XML基础 366 学习目标 366 XML的概念 367 定义...

    Java面试宝典2010版

    16. hibernate进行多表查询每个表中各取几个字段,也就是说查询出来的结果集没有一个实体类与之对应如何解决; 123 17.介绍一下Hibernate的二级缓存 123 18、Spring 的依赖注入是什么意思? 给一个 Bean 的 message ...

    ADO.NET本质论.pdf

    1.4.4 xml和信息集 1.4.5 xml、数据库和统一数据表示 1.5 以数据的中心的应用程序模型 1.6 数据访问api的发展历程 1.7 小结 第2章 ado.net基础 2.1 数据访问和.net体系结构 2.2 两种数据访问模式...

    JAVA入门1.2.3:一个老鸟的JAVA学习心得 PART1(共3个)

    基本信息 作者: 臧萌 出版社:清华大学出版社 ISBN:9787302217831 ...12.2.5 接口——让类集多重类型于一身 344 12.2.6 简化recordTransport()方法 347 12.3 再探接口 349 12.3.1 重温上节中的程序 349...

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    基本信息 作者: 臧萌 出版社:清华大学出版社 ISBN:9787302217831 ...12.2.5 接口——让类集多重类型于一身 344 12.2.6 简化recordTransport()方法 347 12.3 再探接口 349 12.3.1 重温上节中的程序 349...

    Java学习笔记-个人整理的

    {1.3.1}总结}{23}{subsection.1.3.1} {1.4}数据类型}{23}{section.1.4} {1.4.1}整数与浮点数}{23}{subsection.1.4.1} {1.4.1.1}浮点数原理}{24}{subsubsection.1.4.1.1} {1.4.2}格式化输出浮点数}{24}{...

    springmybatis

    MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan Old Java Objects,普通的Java对象)映射成数据库中的记录. orm...

    ssh(structs,spring,hibernate)框架中的上传下载

    这是Hibernate3引入的新特性,对于包含重量级大数据的表字段,这种抽取方式提高了对大字段操作的灵活性,否则加载Tfile对象的结果集时如果总是返回fileContent,这种批量的数据抽取将可以引起数据库的"洪泛效应"。...

    Java 虚拟机面试题全面解析(干货)

    Java 虚拟机面试题全面解析,《深入理解Java虚拟机》干货版,自己总结,希望能够帮助大家,免费下载~什么是类加载机制? 虚拟机和物理机的区别是什么? 运行时栈帧结构 Java方法调用 什么是方法调用? Java的方法调用,...

    Oracle SQL高级编程(资深Oracle专家力作,OakTable团队推荐)--随书源代码

    作者通过总结各自多年的软件开发和教学培训经验,与大家分享了掌握Oracle SQL所独有的丰富功能的技巧所在,内容涵盖SQL执行、联结、集合、分析函数、子句、事务处理等多个方面。读者可以学习到以下几个方面的技巧:...

Global site tag (gtag.js) - Google Analytics