免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5379 | 回复: 0
打印 上一主题 下一主题

mysql JDBC 乱码原因探究 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-06-06 16:02 |只看该作者 |倒序浏览
/*  mysql JDBC 乱码原因探究
参考: mysql文档第10章: Character Set Support
写在前面以方便那些没有耐心看完全文的朋友:
解决方法:
    无论在mysql的配置是什么字符集, 在创建表(或创建数据库)的时候都明确的指定字符集
    如: create table test (....) DEFAULT CHARACTER SET utf8;
    在使用 JDBC 的时候都明确指定字符集参数:
    如: jdbc:mysql://localhost/test?useunicode=true&characterEncoding=utf8
mysql 有4个字符集设定级别:
    服务器级别: 通过编译时指定或在配置文件中通过default-character-set(有两处)指定
    数据库级别:
        CREATE DATABASE db_name
            [[DEFAULT] CHARACTER SET charset_name]
            [[DEFAULT] COLLATE collation_name]
        ALTER DATABASE db_name
            [[DEFAULT] CHARACTER SET charset_name]
            [[DEFAULT] COLLATE collation_name]
    表级别:
        CREATE TABLE tbl_name (column_list)
            [DEFAULT CHARACTER SET charset_name [COLLATE collation_name]]
        ALTER TABLE tbl_name
            [DEFAULT CHARACTER SET charset_name] [COLLATE collation_name]
    列级别:
        col_name {CHAR | VARCHAR | TEXT} (col_length)
        [CHARACTER SET charset_name [COLLATE collation_name]]
补充说明:
    1>  对于上述sql格式中的COLLATE是只得是排序的方法(比如是否大小写敏感排序),
    这里只讨论字符集的设定.
    2>  可以用show character set;来查看MySql中可用的字符集
当然, 以上4个级别的字符集设定从上往下是适用面越来越窄, 但优先级越来越高.
以下是对比说明表, 假设直接用JDBC插入含有汉字的记录.
服务器字符集  列字符集    JDBC URL参数  现象          汉字输入解决方法
latin1          latin1          无      乱码          string.getBytes()
                utf8            无      乱码          无法恢复
                gbk             无      乱码          无法恢复
                latin1          有      运行异常      string.getBytes()
                utf8            有      正常
                gbk             有      正常
utf8            latin1          无/有   运行异常      string.getBytes()
                utf8            无/有   正常
                gbk             无/有   正常
说明:
JDBC URL参数是指
    ?useunicode=true&characterEncoding=gbk 或
    ?useunicode=true&characterEncoding=utf8
运行异常是指
    SQLException: Data too long for column
string.getBytes()是指:
    插入数据库是用 new String(name.getBytes(oneCharSet),iso)
    而读取数据库时用 new String(rs.getString("color").getBytes(iso), oneCharSet)
注意:
    1> 若列字符集正常且又用了 String.getBytes(), 则会运行异常!
    2> 命令行窗口用的是OS默认字符集GBK, 故对于列字符集为urf8的显示会是乱码,
        对列字符集为gbk的也是乱码, 则不知原因!
*/
import java.io.*;
import java.sql.*;
import java.lang.*;
public class T{
    static String user="root";
    static String passwd="123456";
    static String gbk = "gbk";
    static String iso = "ISO-8859-1";
    static String utf = "utf-8";
    static String url="jdbc:mysql://localhost/test";//?useunicode=true&characterEncoding=utf8
    static String driver = "org.gjt.mm.mysql.Driver";
    public static void main(String[] args){
        Connection conn = null;
        try {
            Class.forName(driver).newInstance();
            conn = DriverManager.getConnection(url, user, passwd);
            String name = "张亮亮";
            String addr = "哈工大(威海)";
            String sex = "男";
            String color = "蓝";
            Statement stmt = conn.createStatement();
            String dropSql = "drop table if exists std ";
            String createSql = "create table std ( "
                + "    name    varchar(32) CHARACTER SET latin1,"
                + "    sex     varchar(32) CHARACTER SET gbk,"
                + "    addr    varchar(32) CHARACTER SET utf8,"
                + "    color   varchar(32) "
                + ");";
            String insertSql = "insert into std values('张亮亮"//+new String(name.getBytes(),iso)
                + "','男"//+new String(sex.getBytes(),iso)
                + "','哈工大(威海)"//+new String(addr.getBytes(), iso)
                + "','蓝"//+new String(color.getBytes(),iso)
                + "')";
            String selectSql = "select * from std";
            stmt.executeUpdate( dropSql );      //drop table
            stmt.executeUpdate( createSql );    //create table
            stmt.executeUpdate( insertSql );    //insert    //label_1:
            ResultSet rs = stmt.executeQuery(selectSql);
            while(rs.next()){
                System.out.println(rs.getString("name"));   //label_2:  +", "+new String(rs.getString("name").getBytes(iso))
                System.out.println(rs.getString("sex"));    //label_3:  +", "+new String(rs.getString("sex").getBytes(iso))
                System.out.println(rs.getString("addr"));   //label_4:  +", "+new String(rs.getString("addr").getBytes(iso))
                System.out.println(rs.getString("color"));  //label_5:  +", "+new String(rs.getString("color").getBytes(iso))
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }
};
/*      详细测试
OS: windows 2003
系统字符集: GBK
mysql 版本: 5.0
1>  my.ini 中 default-character-set=utf8
JDBC URL : jdbc:mysql://localhost/test 或者
           jdbc:mysql://localhost/test?useunicode=true&characterEncoding=utf8 或者
           jdbc:mysql://localhost/test?useunicode=true&characterEncoding=gbk
insertSql: insert into std values('张亮亮','男','哈工大(威海)','蓝')"
lable_1:    运行异常: Data too long for column 'name' at row 1
            原因: latin1无法存储汉字, 用 'zhangliangliang' 代替 '张亮亮',
            除了修改列的存储字符集尚无解决方案
lable_2:    zhangliangliang
lable_3:    男
label_4:    哈工大(威海)
label_5:    蓝
Mysql 命令行结果:
mysql> select * from std;
+-----------------+------+-------------------+-------+
| name            | sex  | addr              | color |
+-----------------+------+-------------------+-------+
| zhangliangliang | 鐢?  | 鍝堝伐澶?濞佹捣)      | 钃?   |
+-----------------+------+-------------------+-------+
1 row in set (0.00 sec)
2>  my.ini 中 default-character-set=latin1
JDBC URL : jdbc:mysql://localhost/test?useunicode=true&characterEncoding=utf8 或者
           jdbc:mysql://localhost/test?useunicode=true&characterEncoding=gbk
insertSql: insert into std values('张亮亮','男','哈工大(威海)','蓝')"
lable_1:    运行异常: Data too long for column 'name' at row 1
            Data too long for column 'color' at row 1
            解决方法见最后: 目前先用拼音 zhangliangliang 代替.
lable_2:    zhangliangliang
lable_3:    男
label_4:    哈工大(威海)
label_5:    同lable_1, 用blue代替继续测试.
mysql> select * from std;
+-----------------+------+---------+-------+
| name            | sex  | addr    | color |
+-----------------+------+---------+-------+
| zhangliangliang | ?    | ???(??) | blue  |
+-----------------+------+---------+-------+
1 row in set (0.03 sec)
JDBC URL : jdbc:mysql://localhost/test
insertSql: insert into std values('张亮亮','男','哈工大(威海)','蓝')"
lable_1:    运行无异常
lable_2:    ???
lable_3:    ?      
label_4:    ???(??)     
label_5:    ?
mysql> select * from std;
+------+------+---------+-------+
| name | sex  | addr    | color |
+------+------+---------+-------+
| ???  | ?    | ???(??) | ?     |
+------+------+---------+-------+
1 row in set (0.00 sec)
对于 列字符集为utf8(如addr列), latin1(明确设定(如name列)或默认(如color列))有如下解决方法
(其他UNICODE格式未测试, 用GBK也会出现类似运行时异常):
写入时用:new String(addr.getBytes(), iso)
读取时用:new String(rs.getString("addr").getBytes(iso))
并且在命令行窗口也可以正确显示!(毕竟命令行下只用系统字符集)
*/


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/25218/showart_315962.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP