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

  • 相关阅读:
    iOS 苹果开发证书失效的解决方案(Failed to locate or generate matching signing assets)
    iOS NSArray数组过滤
    App Store2016年最新审核规则
    iOS 根据字符串数目,自定义Label等控件的高度
    iOS 证书Bug The identity used to sign the executable is no longer valid 解决方案
    Entity FrameWork 增删查改的本质
    EF容器---代理类对象
    Entity FrameWork 延迟加载本质(二)
    Entity FrameWork 延迟加载的本质(一)
    Entity FrameWork 增删查改
  • 原文地址:https://www.cnblogs.com/james1207/p/3370838.html
Copyright © 2011-2022 走看看