道理很简单,把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:\programs\mysql5\share\charsets\ |

+--------------------------+------------------------------------+

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

ibatis自定义数据类型在不支持中文的数据库存储汉字的更多相关文章

  1. Sql语句 不支持中文 国外数据库

    由于老美的不支持中文 SQL 语句第一:字段类型改为nvarchar,ntext 第二:强制转化 N update dbo.Role set rolename=N'普通用户' update dbo.T ...

  2. javaScript生成二维码(支持中文,生成logo)

    资料搜索 选择star最多的两个 第一个就是用的比较多的jquery.qrcode.js(但不支持中文,不能带logo)啦,第二个支持ie6+,支持中文,根据第二个源代码,使得,jquery.qrco ...

  3. JS导出PDF插件(支持中文、图片使用路径)

    在WEB上想做一个导出PDF的功能,发现jsPDF比较多人推荐,遗憾的是不支持中文,最后找到pdfmake,很好地解决了此问题.它的效果可以先到http://pdfmake.org/playgroun ...

  4. NSUserdefaults 简介以及存储自定义数据类型的方法

    一.了解NSUserDefaults以及它可以直接存储的类型 NSUserDefaults是一个单例,在整个程序中只有一个实例对象,他可以用于数据的永久保存,而且简单实用,这是它可以让数据自由传递的一 ...

  5. Qt信号之自定义数据类型

    [1]为什么需要自定义数据类型? 内置类型毕竟很有局限性,否则为什么还需要类呢.总之,有时候,我们多么希望信号能发送自定义数据类型. 幸哉~ Qt是支持自定义信号,且自定义信号可以发送自定义数据类型的 ...

  6. TVM自定义数据类型

    TVM自定义数据类型 本文将介绍"自定义数据类型"框架,该框架可在TVM中使用自定义数据类型. 介绍 在设计加速器时,关键是如何近似地表示硬件中的实数.这个问题具有长期的行业标准解 ...

  7. 自主数据类型:在TVM中启用自定义数据类型探索

    自主数据类型:在TVM中启用自定义数据类型探索 介绍 在设计加速器时,一个重要的决定是如何在硬件中近似地表示实数.这个问题有一个长期的行业标准解决方案:IEEE 754浮点标准.1.然而,当试图通过构 ...

  8. netty系列之:轻轻松松搭个支持中文的服务器

    目录 简介 netty的HTTP支持 netty中使用HTTP的原理 100 (Continue) Status 为netty搭建HTTP服务器 总结 简介 之前讲了那么多关于netty的文章,都是讲 ...

  9. 支持中文!秒建 wiki 知识库的开源项目,构建私人知识网络

    不知道有没有人和我一样,觉得自建的东西是互联网上的"自留地".私人空间,有一种自己的一亩三分地随心所欲的痛快. 比如自建的博客想写什么随笔就写什么,不用取悦读者可以自娱自乐:再比如 ...

随机推荐

  1. luoguP3255 [JLOI2013]地形生成 动态规划

    出题人语文真好... 各不相同的标号和高度 = 各不相同的标号 + 单独的高度... 第一问比较简单,考虑从大到小插入,在相同情况下,按关键值从小到大插入 这样子,关键大的元素一定会影响到关键小的元素 ...

  2. [UOJ50]链式反应

    这个题意说人话就是:一棵带标号的有根树,编号满足堆性质,根节点有$x$个儿子是叶子($x\in A$),另外的$2$个儿子也是这样的一棵树,求不同的树的个数 设$f_n$为答案,枚举那两棵子树的大小$ ...

  3. NOIP 解题有感

    算法方面: 在搜索问题上,包括贪心等没有固定算法的题目,还有输出格式(包括输入格式)特别容易出错.这也是解题选手的弱点. 1.做搜索题把步骤先用文字写下来,再转换成代码,以避免敲代码时疏漏某个条件. ...

  4. 【洛谷】P1196 [NOI2002]银河英雄传说【带权并查集】

    P1196 [NOI2002]银河英雄传说 题目描述 公元五八○一年,地球居民迁至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的 ...

  5. HTTP状态码,400,404,500,503

    HTTP状态码(HTTP Status Code) 一些常见的状态码为: 200 - 服务器成功返回网页 400 服务器不理解请求的语法 404 - 请求的网页不存在 503 - 服务不可用 所有状态 ...

  6. python开发_zlib_完整版_博主推荐

    ''' python中的zlib模块提供了压缩和解压缩的方法 实现功能: 读取一个文件的内容,然后把该文件的内容以字符串的形式返回 然后对返回回来的字符串进行压缩处理,然后写入到另一个文件中 同时,也 ...

  7. uoj 48 核聚变反应强度 次小公因数

    [UR #3]核聚变反应强度 Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/48 Description 著名核 ...

  8. yii/helper/Html

    1.生成标签: <?=Html::tag('标签',‘标签中的内容’,[‘标签属性’])?> 举例: <?=Html::tag('p','HelloWorld',['id'=> ...

  9. Struts+Hibernate+Spring常见问题

    http://wanglihu.iteye.com/blog/1897718 1.java.lang.NoClassDefFoundError: org/objectweb/asm/ClassVisi ...

  10. golang(一)-for 循环

    golang 的循环控制中大多还是和java 很相似的 , 不过golang只有一种循环 就是for循环: for 有三个循环控制关键字 : break . continue . goto  其中   ...