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 知识库的开源项目,构建私人知识网络
不知道有没有人和我一样,觉得自建的东西是互联网上的"自留地".私人空间,有一种自己的一亩三分地随心所欲的痛快. 比如自建的博客想写什么随笔就写什么,不用取悦读者可以自娱自乐:再比如 ...
随机推荐
- 通过因特网连接Beaglebone Black
通过因特网连接Beaglebone Black 通过网络连接,可以使你方便地从各种地方以及各种不同的电脑访问到Beaglebone Black.这种连接Beaglebone Black方式通常使用5V ...
- poj 1659 Frogs' Neighborhood( 青蛙的邻居)
Frogs' Neighborhood Time Limit: 5000MS Memory Limit: 10000K Total Submissions: 9639 Accepted: 40 ...
- nyoj 737 石子合并 经典区间 dp
石子合并(一) 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆 ...
- ubuntu16.04安装python3
今天用了下阿里云的云服务器,装个python3真是各种踩坑.记录下吧: ubuntu自带了2.7.想要装3.5并设置为默认python版本. 安装python3.5 sudo add-apt-repo ...
- Elasticsearch 删除索引下的所有数据
下面是head中操作的截图 #清空索引 POST quality_control/my_type/_delete_by_query?refresh&slices=5&pretty { ...
- 常用排序算法的Python实现
冒泡排序 算法思想: 对于一组需要排序的数据,对于相邻的两个数进行比较,使较大(或者较小)的数一直向后推,经过多层排序之后,使整个序列是有序的. 算法实现: def bubble_sort(L): l ...
- PHP视频教程 字符串处理函数(三)
字符串替换函数: str_replace() 替换字符串或数组元素,区分大小,第四个参数可选用于统计替换次数. str_ireplace() 不区分大小写替换 字符串函数比较 strcmp()比较字符 ...
- Hibernate.cfg.xml详解
在搭建Hibernate环境时需要配置Hibernate.cfg.xml配置文件,本文将想详细讲解配置文件的内容. 1.数据库连接信息 配置数据库驱动.(其中name为连接方式,我在这写jdbc的连接 ...
- BZOJ1018 堵塞的交通(线段树)
题目很好明白,然后实现很神奇.首先如果考虑并查集的话,对于删边和加边操作我们无法同时进行.然后暴力分块的话,复杂度是O(n sqrt n) ,不是很优.于是看了题解,发现了线段树的神奇用途. 我们维护 ...
- [BZOJ4554][TJOI2016&&HEOI2016]游戏(匈牙利)
4554: [Tjoi2016&Heoi2016]游戏 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 857 Solved: 506[Sub ...