道理很简单,把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. CSS 笔记——阴影、圆角、旋转、光标

    7. 阴影.圆角.旋转.光标 (1)box-shadow 阴影 基本语法 text-shadow: h-shadow v-shadow blur color; box-shadow: h-shadow ...

  2. BZOJ1030 [JSOI2007]文本生成器(AC自动机)

    做到了AC自动机的题目,复习了一下AC自动机,学习了黄学长代码,这个题呢,我们可以模拟在AC自动机上的操作,dp数组f[i][j]表示前i个字符,我们在AC自动机上处在j号节点的方案数. 我们可以计算 ...

  3. 「学习笔记」wqs二分/dp凸优化

    [学习笔记]wqs二分/DP凸优化 从一个经典问题谈起: 有一个长度为 \(n\) 的序列 \(a\),要求找出恰好 \(k\) 个不相交的连续子序列,使得这 \(k\) 个序列的和最大 \(1 \l ...

  4. 【二分查找-最大化平均值】POJ2976 - Dropping Test

    [题目大意] 给出n组ai和bi,去掉k个使得a的总和除以b的总和最大. [思路] 也就是取(n-k)个数,最大化平均值,见<挑战程序设计竞赛>P144,最后公式为c(x)=((ai-x* ...

  5. PHP配置文件经典漏洞

    phithon师父在小蜜圈里放了一个经典的配置文件写入问题漏洞. <?phpif(!isset($_GET['option'])) die();$str = addslashes($_GET[' ...

  6. 20162327WJH四则运算第二周总结

    学号 20162327 <程序设计与数据结构>四则运算第二次实验报告 1.需求分析 1.本周我们进行了四则运算的后续完善,因为学习的比较欠缺,所以我负责比较简单的部分,就是只包含一个运算符 ...

  7. Mac 下解压NDK .bin文件

    Mac Android Studio 开发NDK,首先下载NDK文件----->android-ndk-r10d-darwin-x86_64.bin 1.打开终端获取文件权限 chmod a+x ...

  8. JDK源码(1.7) -- java.util.Arrays

    java.util.Arrays 源码分析 ------------------------------------------------------------------------------ ...

  9. c# -- 实现浏览功能(备忘)

    最近在做系统的时候,要实现浏览功能,但是由于本人记性一般,每次写完就忘,所以还是写篇随笔,备忘一下,方便以后查看@_@# 实现功能大概如下: 按钮1:点击浏览按钮后,选择文件(类型为.txt),默认位 ...

  10. python画激活函数图像

    导入必要的库 import math import matplotlib.pyplot as plt import numpy as np import matplotlib as mpl mpl.r ...