zoukankan      html  css  js  c++  java
  • ibatis自定义数据类型在不支持中文的数据库存储汉字

    道理很简单,把gbk的汉字转换成iso编码存进数据库就可以了,读出来的时候把iso转换成gbk还原出原始的汉字。
    ibatis可以自定义类型处理器,在这里面做编码转换再适合不过了!
    sqlmap-config.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
    "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
    <sqlMapConfig>
    <settings useStatementNamespaces="true"/>
    <typeHandler javaType="edu.sdust.xujsh.test.type.ChineseString"
    callback="edu.sdust.xujsh.test.type.handler.CnStringTypeHandler" /><!--注意这里的自定义类型处理器-->
    <!-- 使用JDBC的事务管理 -->
    <transactionManager type="JDBC">
    <!-- 数据源 -->
    <dataSource type="SIMPLE">
    <property name="JDBC.Driver" value="com.mysql.jdbc.Driver" />
    <property name="JDBC.ConnectionURL" value="jdbc:mysql://localhost:3306/test" />
    <property name="JDBC.Username" value="root" />
    <property name="JDBC.Password" value="123456" />
    </dataSource>
    </transactionManager>
    <!-- 这里可以写多个实体的映射文件 -->
    <sqlMap resource="User.xml" />
    </sqlMapConfig>

    User.xml:

    <?xml version="1.0" encoding="GB2312"?>
    <!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">
    <sqlMap namespace="User">
        <typeAlias alias="user" type="com.xujsh.test.dto.User"/>
        <resultMap id="userResult" class="user">
            <result property="id" column="id" jdbcType="DECIMAL"/>
            <result property="name" column="name" jdbcType="VARCHAR"/>
            <result property="birth" column="birth" jdbcType="TIMESTAMP"/>
        </resultMap>
        <insert id="insertUser" parameterClass="user"><![CDATA[
            insert into USER (id,name,birth) 
            values (#id#,#name#,#birth#)
        ]]></insert>
        <select id="getUserByUserId" resultMap="userResult" parameterClass="int"><![CDATA[
            select  id,name,birth
            from    USER
            where   id = #id#  
        ]]></select>
    </sqlMap>


    User.xml这里就可以使用ChineseString这种数据类型了,往数据库读数据和写数据的时候会调用CnStringTypeHandler里面的:
    getResult(ResultGetter getter)和setParameter(ParameterSetter setter, Object parameter);
    edu.sdust.xujsh.test.type.ChineseString.java:

    public class ChineseString {
        private String value;//简单的对原始的字符串做一个包装
        public ChineseString(){}
        public ChineseString(String value){
            this.value = value;
        }
        public String getValue() {
            return value;
        }
        public void setValue(String value) {
            this.value = value;
        }
        public String toString() {
            return value;
        }
    }

    edu.sdust.xujsh.test.type.handler.CnStringTypeHandler.java:

    public class CnStringTypeHandler implements TypeHandlerCallback {
        // 中文数据被保存到数据库所使用的字符集
        private static final String STORE_CHARSET  = "GBK";
        // 系统使用的字符集
        private String              systemEncoding = "iso-8859-1";
        /**
         * 从数据库中取数据
         */
        public Object getResult(ResultGetter getter) throws SQLException {
            String value = getter.getString();
            if (value == null) {
                return null;
            } else {
                try {
                    return new ChineseString(new String(value.getBytes(systemEncoding), STORE_CHARSET));
                } catch (UnsupportedEncodingException ue) {
                    return value;
                }
            }
        }
        /**
         * 往数据库写数据
         */
        public void setParameter(ParameterSetter setter, Object parameter) throws SQLException {
            if (parameter != null) {
                ChineseString value = (ChineseString) parameter;
    
    
                if (value.getValue() != null) {
                    try {
                        setter.setString(new String(value.getValue().getBytes(STORE_CHARSET), systemEncoding));
                    } catch (UnsupportedEncodingException ue) {
                        setter.setString(value.getValue());
                    }
                    return;
                }
            }
            setter.setNull(Types.VARCHAR);
        }
        public Object valueOf(String s) {
            return s;
        }
    }

    com.xujsh.test.dto.User.java:

    public class User {
        private int id;
        private ChineseString name;
        private Date birth;
        
        public int getId() {
            return id;
        }
        
        public void setId(int id) {
            this.id = id;
        }
        
        public ChineseString getName() {
            return name;
        }
    
    
        public void setName(ChineseString name) {
            this.name = name;
        }
    
    
        public Date getBirth() {
            return birth;
        }
        
        public void setBirth(Date birth) {
            this.birth = birth;
        }
    
    
        @Override
        public String toString() {
            return "User [id=" + id + ", name=" + name + ", birth=" + birth + "]";
        }
        
    }

    com.xujsh.test.client.Main.java:

    public class Main {
        private static SqlMapClient sqlMapClient = null;
        // 读取配置文件
        static {
            try {
                InputStream in = Main.class.getClassLoader().getResourceAsStream("sqlmap-config.xml");
                sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(in);
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        public static User selectUserById(int id) throws Exception {
            return (User) sqlMapClient.queryForObject("User.getUserByUserId", id);
        }
        public static void insertUser(User user)throws Exception {
           sqlMapClient.insert("User.insertUser", user);
        }
        public static void main(String[] args) throws Exception {
            User u = new User();
            u.setId(123456);
            u.setName(new ChineseString("中国"));
            u.setBirth(new Date());
            Main.insertUser(u);
            u = Main.selectUserById(u.getId());
            System.out.println(u);
        }
    }


    这么做,只要数据库服务器的编码方式兼容iso编码,存储中文都不会有问题。看上去很完美的解决方案,但是还有个问题,存储的数据的长度的变化。

    看一下我们的mysql:
    mysql>  show variables like 'character%';
    +--------------------------+------------------------------------+
    | Variable_name            | Value                              |
    +--------------------------+------------------------------------+
    | character_set_client     | gbk                                |
    | character_set_connection | gbk                                |
    | character_set_database   | utf8                               |
    | character_set_filesystem | binary                             |
    | character_set_results    | gbk                                |
    | character_set_server     | utf8                               |
    | character_set_system     | utf8                               |
    | character_sets_dir       | D:programsmysql5sharecharsets |
    +--------------------------+------------------------------------+
    8 rows in set (0.00 sec)
    数据库是utf8编码的。

    mysql> show create table user G
    *************************** 1. row ***************************
           Table: user
    Create Table: CREATE TABLE `user` (
      `id` int(11) DEFAULT NULL,
      `name` varchar(10) DEFAULT NULL,
      `birth` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTA
    MP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    1 row in set (0.00 sec)

    mysql> select * from user where id =12345;
    +-------+-------+---------------------+
    | id    | name  | birth               |
    +-------+-------+---------------------+
    | 12345 | ???ú   | 2013-10-15 10:22:45 |
    +-------+-------+---------------------+
    1 row in set (0.00 sec)
    mysql> select length(name) from user where id = 12345;
    +--------------+
    | length(name) |
    +--------------+
    |            8 |
    +--------------+
    1 row in set (0.00 sec)

    “中国”的gbk编码是d6 d0 b9 fa,转化成了4个iso字符,在utf-8里面,0080 ~07FF之间的字符占2个字节,这4个字符都在这个范围内,共占8个字节。
    而正常存储"中国"只需要6个字节,一个汉字在utf编码下是3个字节,如下:

    mysql> set names gbk;  --在客户端设置一下编码才能正常的插入中文
    Query OK, 0 rows affected (0.00 sec)

    mysql> insert into user values(123456,'中国',now());
    Query OK, 1 row affected (0.04 sec)
    mysql> select * from user where id = 123456;
    +--------+------+---------------------+
    | id     | name | birth               |
    +--------+------+---------------------+
    | 123456 | 中国    | 2013-10-15 10:39:18 |
    +--------+------+---------------------+
    1 row in set (0.00 sec)
    mysql> select length(name) from user where id = 123456;
    +--------------+
    | length(name) |
    +--------------+
    |            6 |
    +--------------+
    1 row in set (0.00 sec)

    可见,同样是存储“中国”两个汉字,原先要6个字节,现在变为8个字节。
    mysql5里面,varchar(N),指的是N个字符,无论存放的是数字、字母还是UTF8汉字(每个汉字3字节),都可以存放N个,最大大小是65532字节。
    因此,原先我们可以用name varchar(2),现在必须用name varchar(4)。

    ps:set names gbk 是让mysql server 和客户端之间的传输用gbk编码,存储在server上的还是utf8,在客户端查询时仍然需要gbk码,因为cmd命令行默认是gbk编码的。、
    或者是这么搞:
    mysql> set character_set_client=gbk;
    Query OK, 0 rows affected (0.00 sec)
    mysql> set character_set_results=gbk;
    Query OK, 0 rows affected (0.00 sec)
    参考文档:

    http://blog.csdn.net/lovingprince/article/details/2768849

    http://www.cnblogs.com/doit8791/archive/2012/05/28/2522556.html

    源码下载地址:http://download.csdn.net/detail/goldenfish1919/6403209

  • 相关阅读:
    c盘瘦身、windows解除上网限速、贴膜注意事项
    windows7导入k8s用户证书
    ubuntu报错解决和注意事项
    ubuntu默认root密码问题,第一次使用ubuntu需要设置root密码
    java程序员修炼之道
    选择器代码
    css的使用技巧资料
    移动开发的相关资料
    使用phantomjs生成网站快照
    PHP Simple HTML DOM Parser Manual-php解析DOM
  • 原文地址:https://www.cnblogs.com/james1207/p/3370838.html
Copyright © 2011-2022 走看看