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:\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自定义数据类型在不支持中文的数据库存储汉字的更多相关文章
- Sql语句 不支持中文 国外数据库
由于老美的不支持中文 SQL 语句第一:字段类型改为nvarchar,ntext 第二:强制转化 N update dbo.Role set rolename=N'普通用户' update dbo.T ...
- javaScript生成二维码(支持中文,生成logo)
资料搜索 选择star最多的两个 第一个就是用的比较多的jquery.qrcode.js(但不支持中文,不能带logo)啦,第二个支持ie6+,支持中文,根据第二个源代码,使得,jquery.qrco ...
- JS导出PDF插件(支持中文、图片使用路径)
在WEB上想做一个导出PDF的功能,发现jsPDF比较多人推荐,遗憾的是不支持中文,最后找到pdfmake,很好地解决了此问题.它的效果可以先到http://pdfmake.org/playgroun ...
- NSUserdefaults 简介以及存储自定义数据类型的方法
一.了解NSUserDefaults以及它可以直接存储的类型 NSUserDefaults是一个单例,在整个程序中只有一个实例对象,他可以用于数据的永久保存,而且简单实用,这是它可以让数据自由传递的一 ...
- Qt信号之自定义数据类型
[1]为什么需要自定义数据类型? 内置类型毕竟很有局限性,否则为什么还需要类呢.总之,有时候,我们多么希望信号能发送自定义数据类型. 幸哉~ Qt是支持自定义信号,且自定义信号可以发送自定义数据类型的 ...
- TVM自定义数据类型
TVM自定义数据类型 本文将介绍"自定义数据类型"框架,该框架可在TVM中使用自定义数据类型. 介绍 在设计加速器时,关键是如何近似地表示硬件中的实数.这个问题具有长期的行业标准解 ...
- 自主数据类型:在TVM中启用自定义数据类型探索
自主数据类型:在TVM中启用自定义数据类型探索 介绍 在设计加速器时,一个重要的决定是如何在硬件中近似地表示实数.这个问题有一个长期的行业标准解决方案:IEEE 754浮点标准.1.然而,当试图通过构 ...
- netty系列之:轻轻松松搭个支持中文的服务器
目录 简介 netty的HTTP支持 netty中使用HTTP的原理 100 (Continue) Status 为netty搭建HTTP服务器 总结 简介 之前讲了那么多关于netty的文章,都是讲 ...
- 支持中文!秒建 wiki 知识库的开源项目,构建私人知识网络
不知道有没有人和我一样,觉得自建的东西是互联网上的"自留地".私人空间,有一种自己的一亩三分地随心所欲的痛快. 比如自建的博客想写什么随笔就写什么,不用取悦读者可以自娱自乐:再比如 ...
随机推荐
- luoguP3255 [JLOI2013]地形生成 动态规划
出题人语文真好... 各不相同的标号和高度 = 各不相同的标号 + 单独的高度... 第一问比较简单,考虑从大到小插入,在相同情况下,按关键值从小到大插入 这样子,关键大的元素一定会影响到关键小的元素 ...
- [UOJ50]链式反应
这个题意说人话就是:一棵带标号的有根树,编号满足堆性质,根节点有$x$个儿子是叶子($x\in A$),另外的$2$个儿子也是这样的一棵树,求不同的树的个数 设$f_n$为答案,枚举那两棵子树的大小$ ...
- NOIP 解题有感
算法方面: 在搜索问题上,包括贪心等没有固定算法的题目,还有输出格式(包括输入格式)特别容易出错.这也是解题选手的弱点. 1.做搜索题把步骤先用文字写下来,再转换成代码,以避免敲代码时疏漏某个条件. ...
- 【洛谷】P1196 [NOI2002]银河英雄传说【带权并查集】
P1196 [NOI2002]银河英雄传说 题目描述 公元五八○一年,地球居民迁至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的 ...
- HTTP状态码,400,404,500,503
HTTP状态码(HTTP Status Code) 一些常见的状态码为: 200 - 服务器成功返回网页 400 服务器不理解请求的语法 404 - 请求的网页不存在 503 - 服务不可用 所有状态 ...
- python开发_zlib_完整版_博主推荐
''' python中的zlib模块提供了压缩和解压缩的方法 实现功能: 读取一个文件的内容,然后把该文件的内容以字符串的形式返回 然后对返回回来的字符串进行压缩处理,然后写入到另一个文件中 同时,也 ...
- uoj 48 核聚变反应强度 次小公因数
[UR #3]核聚变反应强度 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/48 Description 著名核 ...
- yii/helper/Html
1.生成标签: <?=Html::tag('标签',‘标签中的内容’,[‘标签属性’])?> 举例: <?=Html::tag('p','HelloWorld',['id'=> ...
- Struts+Hibernate+Spring常见问题
http://wanglihu.iteye.com/blog/1897718 1.java.lang.NoClassDefFoundError: org/objectweb/asm/ClassVisi ...
- golang(一)-for 循环
golang 的循环控制中大多还是和java 很相似的 , 不过golang只有一种循环 就是for循环: for 有三个循环控制关键字 : break . continue . goto 其中 ...