字符串是我们设计数据库经常用到的类型,从传统的ASCII格式到UTF-8格式,不同应用需求对应不同的字符类型和长度配置。针对Oracle而言,最常用的类型无外乎char和varchar2两个基本类型。

对于一些中文应用,设计人员就需要重点关注数据表中字符串长度问题。因为在不同的字符串编码方式下,一个中文字符对应的字符byte长度是不同的。比如,一个字段长度设置为10,如果是英文字符就可以容纳10位长度,如果是中文字符就只能容纳最多5位长度。如果采用如UTF-8类宽泛字符集类型,也就3-4个中文字符。

字符串类型的长度定义,这个含义是什么?在Oracle中,我们定义varchar2(10)其实是有两层理解,一则是10个byte位长度,另一则是10个输入字符长度。两种理解前者是技术派,后者理解是从业务应用角度看问题。其实,在Oracle实现层面,两种策略都是支持的。

一、 默认参数设置

笔者选择Oracle 11gR2版本进行测试实验,具体版本号为11.2.0.4。当前字符集为AL32UTF8。

首先实验一下默认条件下,Oracle字符串行为方式。


  1. SQL> create table t (v_char varchar2(10));
  2. Table created
  3.                     
  4. SQL> insert into t values ('ttt');
  5. 1 row inserted
  6. SQL> insert into t values ('tttttttttt');
  7. 1 row inserted
  8. SQL> commit;
  9. Commit complete

默认情况下,对于varchar2(10)类型,英文字符可以容纳下10个字符。下面测试中文字符情况。


  1. SQL> insert into t values ('保护');
  2. 1 row inserted
  3. SQL> commit;
  4. Commit complete
  5. SQL> insert into t values ('保护模式');
  6. insert into t values ('保护模式')
  7. ORA-12899: 列 "TEST"."T"."V_CHAR" 的值太大 (实际值: 12, 最大值: 10)
  8. SQL> insert into t values ('保护模');
  9. 1 row inserted
  10. SQL> commit;
  11. Commit complete

对于长度varchar2(10)的字段类型,三位中文似乎是一个上限。从四位中文输入报错的情况看,当前数据库将一个中文识别为三个长度进行计量。潜含的意思是在UTF-8编码情况下,varchar2(10)表示的是10位byte长度。

那么,控制长度单位是参数是什么呢?

二、 Char & Byte

从Oracle语法上看,varchar2(10)这个10后面其实是包括单位的。默认情况下,我们都不需要去管理这个配置。如果我们不显示的进行指定,Oracle会取自参数nls_length_semantics。


  1. SQL> show parameter nls_length
  2. NAME                                 TYPE        VALUE
  3. ------------------------------------ ----------- ------------------------------
  4. nls_length_semantics                 string      BYTE

在创建数据表和定义字段过程中,我们是可以明确指定长度单位的。Oracle提供了两种选择,一个是byte,另一个是char。


  1. SQL> create table t_char (v_char varchar2(10 char), v_byte varchar2(10));
  2. Table created
  3. SQL> desc t_char;
  4. Name   Type              Nullable Default Comments
  5. ------ ----------------- -------- ------- --------
  6. V_CHAR VARCHAR2(10 CHAR) Y                         
  7. V_BYTE VARCHAR2(10)      Y      

当前是byte默认单位模式下(注意这个前提),v_char字段明显显示10位字符长度。


  1. SQL> insert into t_char(v_char) values ('tttttttttt');
  2. 1 row inserted
  3. SQL> insert into t_char(v_char) values ('ttttttttttt');
  4. insert into t_char(v_char) values ('ttttttttttt')
  5. ORA-12899: 列 "TEST"."T_CHAR"."V_CHAR" 的值太大 (实际值: 11, 最大值: 10)
  6. SQL> commit;
  7. Commit complete

10位英文字符测试通过,下面试验一下中文字符。


  1. SQL> insert into t_char(v_char) values ('实验实验实验实验实验');
  2. 1 row inserted
  3. SQL> commit;
  4. Commit complete
  5. SQL> insert into t_char(v_char) values ('实验实验实验实验实验实验');
  6. insert into t_char(v_char) values ('实验实验实验实验实验实验')
  7. ORA-12899: 列 "TEST"."T_CHAR"."V_CHAR" 的值太大 (实际值: 12, 最大值: 10)
  8. SQL> select * from t_char;
  9. V_CHAR                                   V_BYTE
  10. ---------------------------------------- ----------
  11. tttttttttt                              
  12. 实验实验实验实验实验       

十个中文字符可以容纳,使用dump查看存储结构编码。


  1. SQL> select dump(v_char, 1016) as a from t_char;
  2. A
  3. ------------------------------------------------------------------------------------------------------------------------------
  4. Typ=1 Len=10 CharacterSet=AL32UTF8: 74,74,74,74,74,74,74,74,74,74
  5. Typ=1 Len=30 CharacterSet=AL32UTF8: e5,ae,9e,e9,aa,8c,e5,ae,9e,e9,aa,8c,e5,ae,9e,e9,aa,8c,e5,ae,9e,e9,aa,8c,e5,ae,9e,e9,aa,8c

说明在char计量单位下,数据库不会按照存储技术结构进行长度选取,而是根据实际存放长度进行计量。

三、 参数变更实验

注意这个参数修改不需要重启,但需要重启数据库才会生效。


  1. SQL> show parameter nls_leng
  2. NAME                                 TYPE        VALUE
  3. ------------------------------------ ----------- ------------------------------
  4. nls_length_semantics                 string      BYTE
  5. SQL> alter system set nls_length_semantics=char scope=both;
  6. System altered
  7. SQL> show parameter nls_leng
  8. NAME                                 TYPE        VALUE
  9. ------------------------------------ ----------- ------------------------------
  10. nls_length_semantics                 string      CHAR

此时仅修改了参数,但没有重启数据库,下面进行实验。


  1. SQL> create table t_test (v_char varchar2(10));
  2. Table created
  3. SQL> desc t_test;
  4. Name   Type         Nullable Default Comments
  5. ------ ------------ -------- ------- --------
  6. V_CHAR VARCHAR2(10) Y                        
  7. SQL> insert into t_test values ('实验实验实验');
  8. insert into t_test values ('实验实验实验')
  9. ORA-12899: 列 "TEST"."T_TEST"."V_CHAR" 的值太大 (实际值: 18, 最大值: 10)

可以看到长度配置默认单位没有变化,依然是byte的效果。如果需要参数生效,需要重新启动数据库实例。


  1. SQL> shutdown immediate
  2. SQL> startup
  3. SQL> show parameter nls_leng
  4. NAME                                 TYPE        VALUE
  5. ------------------------------------ ----------- ------------------------------
  6. nls_length_semantics                 string      CHAR

再次测试,发现能成功了。


  1. SQL> create table t_test (v_char varchar2(10));
  2. Table created           
  3. SQL> insert into t_test values ('实验实验实验实验实验');
  4. 1 row inserted
  5. SQL> commit;
  6. Commit complete
  7. SQL> select * from t_test;
  8. V_CHAR
  9. ----------------------------------------
  10. 实验实验实验实验实验

同时,过去定义为byte计量的单元字段也被明显显示出来。


  1. SQL> desc t_char
  2. Name   Type              Nullable Default Comments
  3. ------ ----------------- -------- ------- --------
  4. V_CHAR VARCHAR2(10)      Y                        
  5. V_BYTE VARCHAR2(10 BYTE) Y                         
  6. SQL> desc t_byte
  7. Name   Type              Nullable Default Comments
  8. ------ ----------------- -------- ------- --------
  9. V_CHAR VARCHAR2(10 BYTE) Y    

四、 结论

数据库字段长度在传统的应用开发领域是一个比较重要的问题。传统观点认为这部分应该体现业务逻辑思想,也就是将字段的长度与业务逻辑对应,甚至可以通过数据库来控制用户操作。但是,由于字符串长度因素、软件设计思想的变化影响,这部分逻辑越来越被推到了界面和应用逻辑层次来完成。

对Oracle而言,提供char方式定义字段是备选的策略。在确实需要数据库严格反应业务逻辑的情况下,是种不错的选择。

</article>

[转帖]聊聊字符串数据长度和nls_length_semantics参数的更多相关文章

  1. InnerException 消息是“反序列化对象 属于类型 *** 时出现错误。读取 XML 数据时,超出最大字符串内容长度配额 (8192)。(注意细节)

    WEB站点在调用我们WCF服务的时候,只要传入的参数过长,就报如下错误: 格式化程序尝试对消息反序列化时引发异常: 尝试对参数 http://tempuri.org/ 进行反序列化时出错: formD ...

  2. Web Service 或 WCF调用时读取 XML 数据时,超出最大字符串内容长度配额(8192)解决方法

    1.调用服务时服务 当我们使用 Web Service 或 WCF 服务时,常把读取的数据转化为string类型(xml格式),当数据量达到一 定数量时,会出现以下异常: 错误:格式化程序尝试对消息反 ...

  3. 读取 XML 数据时,超出最大字符串内容长度配额 (8192)

    格式化程序尝试对消息反序列化时引发异常: 尝试对参数 http://www.thermo.com/informatics/xmlns/limswebservice 进行反序列化时出错: Process ...

  4. WCF传送大数据时的错误“ 超出最大字符串内容长度配额”

    格式化程序尝试对消息反序列化时引发异常: 尝试对参数 http://tempuri.org/ 进行反序列化时出错: GetLzdtArticleResult.InnerException 消息是“反序 ...

  5. ASP.NET MVC Json()处理大数据异常解决方法,字符串的长度超过了为 maxJsonLength

    问题: 使用 JSON JavaScriptSerializer 进行序列化或反序列化时出错.字符串的长度超过了为 maxJsonLength 属性设置的值. <system.web.exten ...

  6. C#编程中的Image/Bitmap与base64的转换及 Base-64 字符数组或字符串的长度无效问题 解决

    最近用base64编码传图片遇到了点问题,总结下. 首先总结下base64编码的逻辑,来自网络:https://www.cnblogs.com/zhangchengye/p/5432276.html ...

  7. Redis中String类型的Value最大可以容纳数据长度

    项目中使用redis存储,key-value方式,在Redis中字符串类型的Value最多可以容纳的数据长度是512M 官方信息: A String value can be at max 512 M ...

  8. JSON JavaScriptSerializer 字符串的长度超过了为 maxJsonLength 属性设置的值。

    1.序列化: 以下代码在对象过大时会报错:进行序列化或反序列化时出错.字符串的长度超过了为 maxJsonLength 属性设置的值. //jsonObj比较大的时候会报错 var serialize ...

  9. Base-64 字符数组或字符串的长度无效等问题解决方案

    项目特殊需要,调用ActiveX三维控件进行控件某一特殊部位的截图操作,这个截图保存由ActiveX控件控制保存到本地是没问题的,现在需要将这个截图上传到服务器,多人共享,就牵扯到需要读取本地文件…… ...

  10. JS获取字符串实际长度(包含汉字)

    方法一: var jmz = {}; jmz.GetLength = function(str) { ///<summary>获得字符串实际长度,中文2,英文1</summary&g ...

随机推荐

  1. ubuntu 20.0.4 LTS 配置国内apt-get源

    https://blog.csdn.net/wangyijieonline/article/details/105360138 更换阿里源 要知道当前系统的代号,可以用以下命令: lsb_releas ...

  2. 在ubuntu下将virtualbox虚拟机的磁盘重设大小的方法

    1.VBoxManage modifyhd /home/beyond/xxx.vdi --resize 20480 {20480(单位:M)是你要扩容之后的总大小,/home/beyond 是你存放 ...

  3. Windows使用docker踩坑记录

    一.安装踩坑 安装时会让你选择:是否使用Windows容器 Use Windows containers instead of Linux containers(this can be changed ...

  4. 物联网通信技术最全科普!你一定要了解的NB-IoT

    摘要: NB-IoT(窄带蜂窝物联网)产业正在迅速崛起. 我们这一期的文章主要是普及一些NB-IoT通信技术的相关知识点.也希望你能get到属于自己的知识盲点! 一.前言 NB-IoT(窄带蜂窝物联网 ...

  5. 带你聚焦GaussDB(DWS)存储时游标使用

    摘要:游标是一种数据处理方法,提供了在查询结果集中进行逐行遍历浏览数据的方法,也可以将游标当做上下文区域的句柄或者指针,借助游标对指定位置的数据进行查询与处理. 本文分享自华为云社区<Gauss ...

  6. 华为云数据库GaussDB(for Influx)揭秘第二期:解密GaussDB(for Influx)的数据压缩

    摘要:物联网设备产生的数据是典型的时序数据,而时序数据库是存储时序数据的专业数据库系统,因此数据压缩对时序数据库来说是一项必不可少的能力. 本文分享自华为云社区<华为云数据库GaussDB(fo ...

  7. 快来一起玩转LiteOS组件:RHas

    摘要:RHash是一个C语言编写的哈希函数库,用于计算和验证磁力链接和各种消息摘要的控制台实用程序. 本文分享自华为云社区<LiteOS组件尝鲜-玩转RHas>,作者:Lionlace . ...

  8. Windows系统快速安装Superset 0.37

    Windows系统安装Superset 0.37 Superset 是一款由 Airbnb 开源的"现代化的企业级 BI(商业智能) Web 应用程序",其通过创建和分享 dash ...

  9. Solon2 开发之IoC,二、构建一个 Bean 的三种方式

    1.手动 简单的构建: //生成普通的Bean Solon.context().wrapAndPut(UserService.class, new UserServiceImpl()); //生成带注 ...

  10. PPT 快速生成图片墙

    图片墙有什么用? 掌握以后,做封面就不慌了.减轻了找素材的压力 手动排列 插入任意大小矩形,好处,不需要对插入的张图片单独调整大小 右击进行组合,然后拉面整个PPT页面 插入8张图片 设置蒙版 画个大 ...