一条诡异的insert语句
问题背景
有同事反馈在mysql上面执行一条普通的insert语句,结果报错,
execute failed due to >>> Incorrect string value: '\xA1;offl...' for
column 'biz_info' at row 1
经过半天的折腾,终于搞清楚了来龙去脉,这里简单给大家分享下。为了方便说明,我将测试例子中的表和语句简化,但不影响问题重现。
问题复现
连接字符集:UTF8
表结构:
CREATE TABLE `ggg` (
`id` int(11) DEFAULT NULL,
`c` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=gbk;
root@test 06:13:48>insert into ggg
values(1,concat('cardName:校园网',char(59),'offlineCardType:campus'));
Query OK, 1 row affected, 1 warning (2.51
sec)
root@test 06:14:36>show warnings\G
*************************** 1. row
***************************
Level: Warning
Code: 1366
Message: Incorrect string value:
'\x91;offl...' for column 'c' at row 1
查看结果
root@test 06:16:06>select * from ggg
where id=1;
*************************** 1. row
***************************
id: 1
c: cardName:鏍″洯缃
问题分析
从报错的结果来看,感觉是字符集转换引起的问题,而且由于连接串的字符集是UTF8,表的字符集是GBK,更容易引起怀疑。但是,即使是字符集转换,也不应该导致插入报错,因为语句中的中文字符“校园网"都是普通汉字,UTF8->GBK不应该存在问题。那我们在回过头来看看insert语句,唯一特殊的是使用了concat和char两个函数。会不会跟这两个函数有关系?char(59)实际是字符“;”,为了验证想法,做了两个实验:
- 将char(59)替换成';'
insert into ggg values(1,concat('cardName:校园网',';','offlineCardType:campus'));
2.设置连接串字符集为GBK
insert into ggg
values(1,concat('cardName:校园网',char(59),'offlineCardType:campus'));
果然,两种情况执行结果都是OK的,查询结果如下:
root@test 09:22:32>select * from
ggg\G
*************************** 1. row
***************************
id: 1
c: cardName:鏍″洯缃
*************************** 2. row
***************************
id: 1
c: cardName:校园网;offlineCardType:campus
*************************** 3. row
***************************
id: 1
c: cardName:校园网;offlineCardType:campus
跟踪了下源代码,找到了原因。char()函数返回的是一个binary类型字符串,在进行concat时,会导致'cardName:校园网'字符串到binary的转换。转换前,mysql将字符串‘cardName:校园网’看作是9个英文字符和3个汉字字符;转换后,mysql将其看作是18个字节的二进制串,其中,UTF8字符集的三个汉字“校园网”占了9个字节。由于目标表字符集是GBK,因此在入库时,还会发生一次binary到GBK的转码,“校园网”的二级制编码是E6A0A1 E59BAD E58DA1,在转码过程中,由于GBK字符集只包含一个字节(编码值<128)和二个字节的字符(汉字和特殊字符),“校园网”的二进制串会按照两个字节拆分E6A0 A1E5 9BAD E58D A1,前面四个变为“鏍″洯缃”,解析到A1时,由于A1既不是单字节字符,又不能与后面的字节组成一个合法的GBK字符,导致转换出错。
现在就很好解释为啥改变语句后,两种情况都OK了。第一种情况,将char(59)直接替换成‘;’,由于不涉及UF8到binary的转换,只有utf8到gbk转码的过程,这个转换是OK的,不会出现乱码;第二种情况,将连接串的字符集设置为GBK,那么会涉及GBK到binary的转换,然后再从binary转换到GBK,由于整个转换过程并没有二进制数据丢失,所以也是OK的。
问题产生的两个关键点
- 连接字符集与表字符集不匹配
- 使用了char函数
解决办法
1.char函数提供了using语法来实现返回特定字符集的字符串,比如:char(59 using utf8)
2.保证连接字符集与表字符集一致。
一条诡异的insert语句的更多相关文章
- 24_MySQL插入insert语句
本节涉及SQL语句: -- MYSQL 基础操作 1.插入insert语句 INSERT INTO t_dept(deptno,dname,loc) VALUES(70,"后勤部" ...
- 一条insert语句批量插入多条记录
一条insert语句批量插入多条记录 常见的insert语句,向数据库中,一条语句只能插入一条数据: insert into persons (id_p, lastname , firstName, ...
- laravel 获取上一条insert语句产生的id
<?php //頭部引入DB類 use Illuminate\Support\Facades\DB; //在方法中獲取获取上一条insert语句产生的id $id = DB::getPdo()- ...
- 跟随一条insert语句, 进入TiDB的源码世界(上)
TiDB是Google F1的开源实现: TiDB实现了基于mvcc的乐观锁,在线表结构变更,基于时间戳的数据线性一致性,等等: 为了可靠性,TiDB和Oracle一样,维护了百万级别的自动化测试用例 ...
- Sql Server系列:Insert语句
1 INSERT语法 [ WITH <common_table_expression> [ ,...n ] ] INSERT { [ TOP ( expression ) [ PERCEN ...
- 如何判断一条sql(update,delete)语句是否执行成功
如何判断一条sql(update,delete)语句是否执行成功 catch (SQLException e) { } catch不到错误应该就成功了. ============== ...
- sql插入多条数据的sql语句
sql插入多条数据的sql语句 有三种方法:1.InSert Into <表名>(列名)Select <列名>From <源表名>如:INSERT INTO Ton ...
- SQL Insert语句数据以以unicode码存储 解决存储数据出现乱码的问题
写了个读取原始的文本数据导入数据库的工具 ,最后发现空中有几个值是乱码 例如 原始数据是 :Bjørn 存到数据库中是 Bj?rn 研究半天发现是一直以来忽略了一个标记‘N’ 2条 Insert 语句 ...
- 老李分享:MySql的insert语句的性能优化方案
老李分享:MySql的insert语句的性能优化方案 性能优化一直是测试人员比较感兴趣的内容,poptest在培训学员的时候也加大了性能测试调优的方面的内容,而性能优化需要经验的积累,经验的积累依 ...
随机推荐
- 炉石传说 C# 开发笔记 (源代码整理公开)
源代码已经整理过了,去除了不需要的项目. 注意:以前文章中出现过的Git已经变更过了,请以前关注过,Fork过的朋友,重新Fork一下. GitHub地址 卡牌XML文件的做成:(Git上面是没有XM ...
- jquery练习
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- border-style 属性
border-style 属性用于设置元素所有边框的样式,或者单独地为各边设置边框样式. 只有当这个值不是 none 时边框才可能出现. 例子 1 border-style:dotted solid ...
- 回文字算法(java版本)
package com.gdh.backtext;import java.util.HashMap;import java.util.Map;import java.util.Map.Entry; p ...
- nodejs中全局变量
1.global 类似于客户端javascript运行环境中的window module1.js: module.exports={}; //耻辱的使用了全局变量 global.varA = &quo ...
- Welcome Phalcon
Welcome! 欢迎来到 Phalcon 框架, 一种崭新的 PHP 框架.我们的使命是给开发者一个开发 web 站点和应用的高级工具,让开发者不用担心框架的性能问题. Phalcon 是什么? P ...
- 网页引用本地电脑的字体 css设置浏览器会不显示的解决办法
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 读jQuery源码 - Deferred
Deferred首次出现在jQuery 1.5中,在jQuery 1.8之后被改写,它的出现抹平了javascript中的大量回调产生的金字塔,提供了异步编程的能力,它主要服役于jQuery.ajax ...
- Ioc容器Autofac系列(1)-- 初窥
一.前言 第一次接触Autofac是因为CMS系统--Orchard,后来在一个开源爬虫系统--NCrawler中也碰到过,随着深入了解,我越发觉得Ioc容器是Web开发中必不可少的利器.那么,Io ...
- Android存储访问及目录
Android存储访问及目录 Android的外部存储 Android支持外部存储(case-insensitive filesystem with immutable POSIX permissio ...