我的日常

登录/注册
您现在的位置:论坛 资料库 数据库开发 > mysql中char和varchar(n)中n的问题字符数还是字节数
总共48087条微博

动态微博

查看: 1855|回复: 0

mysql中char和varchar(n)中n的问题字符数还是字节数

[复制链接]
admin    

1244

主题

544

听众

1万

金钱

管理员

  • TA的每日心情

    2021-2-2 11:21
  • 签到天数: 36 天

    [LV.5]常住居民I

    管理员

    跳转到指定楼层
    楼主
    发表于 2015-05-24 18:39:06 |只看该作者 |倒序浏览

    【问题来源】将设计的数据库表展示的时候,yu哥问我,你的那个top_info字段定义的类型是varchar(100),为什么是100呢,这100的长度能存多少个中文?
    当时的想法就是,这个100能存多少个中文和数据库的编码方式有关,具体怎么个有关发还真是没有细细探究。为了搞清这一系列的问题,我百度了一下,但是网上的答案千奇百怪,很不给力,只能自己摸索了。
    首先需要明确的是:utf8编码方式下,一个中文占3个字节;而gbk编码下,一个中文占2个字节。这个我们可以使用varchar类型存储一个字段vname,然后分别向其中添加一个汉字和英文,然后select length(vname) from tablename;然后我们添加进去的数据占多少个字节一目了然。再用select char_length(vname) from tablename,你会发现二者的关系就是上述内容。
    回到那个问题,这100的长度到底能存多少个中文,既然一个中文占3个字节,是不是就只能存100/3=33个中文呢??换句话说,100这个数字是字节数,还是字符数!?为此我做了如下测试:
    在linux上的mysql中定义了下表
    CREATE TABLE `test` (
      `v` varchar(4) default NULL,
      `c` char(4) default NULL
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
    即如下图

    然后insert into test values (‘围脖你好’,’围脖你好’);有2个warning,select之后才发现
    只存进去一个“新”字,后面的全丢了。这就说明,varchar(4)和char(4)中的4是字节数,即100是字节数,只能存33个中文字符。(备注:如果我们存储的字符串长度超过预定义的长度,mysql仍然可以存储成功,只是会提示warning,会将超出的部分自动截断。)

    答案貌似明确了,但紧接着问题又来了!

    因为以前听说,这个varchar(n)和char(n)中的n指的是存储的字符数,这不和我刚才做的测试完全不符吗?所以我又在本地windows下的mysql中做了同样的操作,建相同的表,插入相同的数据,看到结果,我傻眼了!!
    insert into test values (‘围脖你好’,’围脖你好’);并未warning,而是query OK!select之后发现,这四个中文竟然都存进去了,这也就说明我们刚才定义的那个char(4)和varchar(4)中的4是字符数,而非字节数,这么说来,那100就是可以存100个中文字符了,这不完全将刚才的那个结论颠覆了??可是这两个结果都是对的啊,只是环境不同而已。

    这样的话,那我们以后定义char和varchar字段还要先判断一下该环境下这个(n)到底代表的啥?是字节还是字符?

    不甘心,想搞清楚原因,为何会出现这样的差别?于是yu哥给我说了这样一个命令
    Show variable like ‘%char%’;
    这下清晰了,linux下的和windows下的mysql相关变量编码定义完美呈现


    实际上,character_set_client、character_set_connection、character_set_results是可以改变的,这个可以使用set names gbk/utf8, 只是为了和客户端编码页保持一致,不会乱码,如果客户端编辑页设定的文档是utf8,那么我们自然要set names utf8了,gbk同理。这个命令只会改变显示问题,底部的database的编码还是不会因为这个命令而受到影响的。包括server、system也不会随之改变,这时我们对比上下两张表,他们的server和system以及database的编码发现Linux下的都是Latin1,而windows下的这个都是utf8,


    我们知道Latin1都是存储字节为单位的字符比如数字、字母,一个Latin字符只占一个字节,而utf8存储的种类繁多,字符所占的字节数也就不确定了,utf8具有统一功能,其实网上大多是说char(n)存的是n个字符,就是因为此处的编码都是utf8的,utf8屏蔽了中文和英文和数字的显示区别,他们都是一个字符,所以定义的时候那个n就代表了字符的个数,具体占多少个字节是根据他们自身字符串的长度定的,比如char(100)存储100个中文,那么占300个字节,存100个字母,就占100个字节。
    但是这好像并不能说明这n代表的是字符而不是字节!
    什么情况下它代表字节,什么情况下代表字符?这和我们刚才列出的那些变量的编码有什么关系?。。。。。。继续探索中,求指点!

    注:部分描述可能存在问题,望提出宝贵的意见和指导。

    附:char与varchar的部分总结比较(与此文无关)




    科帮网 1、本主题所有言论和图片纯属会员个人意见,与本社区立场无关
    2、本站所有主题由该帖子作者发表,该帖子作者与科帮网享有帖子相关版权
    3、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和科帮网的同意
    4、帖子作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任
    5、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
    6、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意
    7、科帮网管理员和版主有权不事先通知发贴者而删除本文


    JAVA爱好者①群:JAVA爱好者① JAVA爱好者②群:JAVA爱好者② JAVA爱好者③ : JAVA爱好者③

    快速回复
    您需要登录后才可以回帖 登录 | 立即注册

       

    关闭

    站长推荐上一条 /1 下一条

    发布主题 快速回复 返回列表 联系我们 官方QQ群 科帮网手机客户端
    快速回复 返回顶部 返回列表