[转帖]聊聊字符串数据长度和nls_length_semantics参数
字符串是我们设计数据库经常用到的类型,从传统的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字符串行为方式。
-
SQL> create table t (v_char varchar2(10));
-
Table created
-
-
SQL> insert into t values ('ttt');
-
1 row inserted
-
-
SQL> insert into t values ('tttttttttt');
-
1 row inserted
-
-
SQL> commit;
-
Commit complete
默认情况下,对于varchar2(10)类型,英文字符可以容纳下10个字符。下面测试中文字符情况。
-
SQL> insert into t values ('保护');
-
1 row inserted
-
-
SQL> commit;
-
Commit complete
-
-
SQL> insert into t values ('保护模式');
-
insert into t values ('保护模式')
-
ORA-12899: 列 "TEST"."T"."V_CHAR" 的值太大 (实际值: 12, 最大值: 10)
-
-
SQL> insert into t values ('保护模');
-
1 row inserted
-
-
SQL> commit;
-
Commit complete
对于长度varchar2(10)的字段类型,三位中文似乎是一个上限。从四位中文输入报错的情况看,当前数据库将一个中文识别为三个长度进行计量。潜含的意思是在UTF-8编码情况下,varchar2(10)表示的是10位byte长度。
那么,控制长度单位是参数是什么呢?
二、 Char & Byte
从Oracle语法上看,varchar2(10)这个10后面其实是包括单位的。默认情况下,我们都不需要去管理这个配置。如果我们不显示的进行指定,Oracle会取自参数nls_length_semantics。
-
SQL> show parameter nls_length
-
-
NAME TYPE VALUE
-
------------------------------------ ----------- ------------------------------
-
nls_length_semantics string BYTE
在创建数据表和定义字段过程中,我们是可以明确指定长度单位的。Oracle提供了两种选择,一个是byte,另一个是char。
-
SQL> create table t_char (v_char varchar2(10 char), v_byte varchar2(10));
-
Table created
-
-
SQL> desc t_char;
-
-
Name Type Nullable Default Comments
-
------ ----------------- -------- ------- --------
-
V_CHAR VARCHAR2(10 CHAR) Y
-
V_BYTE VARCHAR2(10) Y
当前是byte默认单位模式下(注意这个前提),v_char字段明显显示10位字符长度。
-
SQL> insert into t_char(v_char) values ('tttttttttt');
-
1 row inserted
-
-
SQL> insert into t_char(v_char) values ('ttttttttttt');
-
insert into t_char(v_char) values ('ttttttttttt')
-
ORA-12899: 列 "TEST"."T_CHAR"."V_CHAR" 的值太大 (实际值: 11, 最大值: 10)
-
-
SQL> commit;
-
Commit complete
10位英文字符测试通过,下面试验一下中文字符。
SQL> insert into t_char(v_char) values ('实验实验实验实验实验'); 1 row inserted SQL> commit; Commit complete SQL> insert into t_char(v_char) values ('实验实验实验实验实验实验'); insert into t_char(v_char) values ('实验实验实验实验实验实验') ORA-12899: 列 "TEST"."T_CHAR"."V_CHAR" 的值太大 (实际值: 12, 最大值: 10) SQL> select * from t_char; V_CHAR V_BYTE ---------------------------------------- ---------- tttttttttt 实验实验实验实验实验
十个中文字符可以容纳,使用dump查看存储结构编码。
-
SQL> select dump(v_char, 1016) as a from t_char;
-
-
A
-
------------------------------------------------------------------------------------------------------------------------------
-
Typ=1 Len=10 CharacterSet=AL32UTF8: 74,74,74,74,74,74,74,74,74,74
-
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计量单位下,数据库不会按照存储技术结构进行长度选取,而是根据实际存放长度进行计量。
三、 参数变更实验
注意这个参数修改不需要重启,但需要重启数据库才会生效。
-
SQL> show parameter nls_leng
-
-
NAME TYPE VALUE
-
------------------------------------ ----------- ------------------------------
-
nls_length_semantics string BYTE
-
-
SQL> alter system set nls_length_semantics=char scope=both;
-
System altered
-
-
SQL> show parameter nls_leng
-
-
NAME TYPE VALUE
-
------------------------------------ ----------- ------------------------------
-
nls_length_semantics string CHAR
此时仅修改了参数,但没有重启数据库,下面进行实验。
-
SQL> create table t_test (v_char varchar2(10));
-
Table created
-
-
SQL> desc t_test;
-
-
Name Type Nullable Default Comments
-
------ ------------ -------- ------- --------
-
V_CHAR VARCHAR2(10) Y
-
-
SQL> insert into t_test values ('实验实验实验');
-
insert into t_test values ('实验实验实验')
-
ORA-12899: 列 "TEST"."T_TEST"."V_CHAR" 的值太大 (实际值: 18, 最大值: 10)
可以看到长度配置默认单位没有变化,依然是byte的效果。如果需要参数生效,需要重新启动数据库实例。
-
SQL> shutdown immediate
-
SQL> startup
-
-
SQL> show parameter nls_leng
-
-
NAME TYPE VALUE
-
------------------------------------ ----------- ------------------------------
-
nls_length_semantics string CHAR
再次测试,发现能成功了。
-
SQL> create table t_test (v_char varchar2(10));
-
Table created
-
-
SQL> insert into t_test values ('实验实验实验实验实验');
-
1 row inserted
-
-
SQL> commit;
-
Commit complete
-
-
SQL> select * from t_test;
-
-
V_CHAR
-
----------------------------------------
-
实验实验实验实验实验
同时,过去定义为byte计量的单元字段也被明显显示出来。
-
SQL> desc t_char
-
-
Name Type Nullable Default Comments
-
------ ----------------- -------- ------- --------
-
V_CHAR VARCHAR2(10) Y
-
V_BYTE VARCHAR2(10 BYTE) Y
-
-
SQL> desc t_byte
-
-
Name Type Nullable Default Comments
-
------ ----------------- -------- ------- --------
-
V_CHAR VARCHAR2(10 BYTE) Y
四、 结论
数据库字段长度在传统的应用开发领域是一个比较重要的问题。传统观点认为这部分应该体现业务逻辑思想,也就是将字段的长度与业务逻辑对应,甚至可以通过数据库来控制用户操作。但是,由于字符串长度因素、软件设计思想的变化影响,这部分逻辑越来越被推到了界面和应用逻辑层次来完成。
对Oracle而言,提供char方式定义字段是备选的策略。在确实需要数据库严格反应业务逻辑的情况下,是种不错的选择。
</article>
[转帖]聊聊字符串数据长度和nls_length_semantics参数的更多相关文章
- InnerException 消息是“反序列化对象 属于类型 *** 时出现错误。读取 XML 数据时,超出最大字符串内容长度配额 (8192)。(注意细节)
WEB站点在调用我们WCF服务的时候,只要传入的参数过长,就报如下错误: 格式化程序尝试对消息反序列化时引发异常: 尝试对参数 http://tempuri.org/ 进行反序列化时出错: formD ...
- Web Service 或 WCF调用时读取 XML 数据时,超出最大字符串内容长度配额(8192)解决方法
1.调用服务时服务 当我们使用 Web Service 或 WCF 服务时,常把读取的数据转化为string类型(xml格式),当数据量达到一 定数量时,会出现以下异常: 错误:格式化程序尝试对消息反 ...
- 读取 XML 数据时,超出最大字符串内容长度配额 (8192)
格式化程序尝试对消息反序列化时引发异常: 尝试对参数 http://www.thermo.com/informatics/xmlns/limswebservice 进行反序列化时出错: Process ...
- WCF传送大数据时的错误“ 超出最大字符串内容长度配额”
格式化程序尝试对消息反序列化时引发异常: 尝试对参数 http://tempuri.org/ 进行反序列化时出错: GetLzdtArticleResult.InnerException 消息是“反序 ...
- ASP.NET MVC Json()处理大数据异常解决方法,字符串的长度超过了为 maxJsonLength
问题: 使用 JSON JavaScriptSerializer 进行序列化或反序列化时出错.字符串的长度超过了为 maxJsonLength 属性设置的值. <system.web.exten ...
- C#编程中的Image/Bitmap与base64的转换及 Base-64 字符数组或字符串的长度无效问题 解决
最近用base64编码传图片遇到了点问题,总结下. 首先总结下base64编码的逻辑,来自网络:https://www.cnblogs.com/zhangchengye/p/5432276.html ...
- Redis中String类型的Value最大可以容纳数据长度
项目中使用redis存储,key-value方式,在Redis中字符串类型的Value最多可以容纳的数据长度是512M 官方信息: A String value can be at max 512 M ...
- JSON JavaScriptSerializer 字符串的长度超过了为 maxJsonLength 属性设置的值。
1.序列化: 以下代码在对象过大时会报错:进行序列化或反序列化时出错.字符串的长度超过了为 maxJsonLength 属性设置的值. //jsonObj比较大的时候会报错 var serialize ...
- Base-64 字符数组或字符串的长度无效等问题解决方案
项目特殊需要,调用ActiveX三维控件进行控件某一特殊部位的截图操作,这个截图保存由ActiveX控件控制保存到本地是没问题的,现在需要将这个截图上传到服务器,多人共享,就牵扯到需要读取本地文件…… ...
- JS获取字符串实际长度(包含汉字)
方法一: var jmz = {}; jmz.GetLength = function(str) { ///<summary>获得字符串实际长度,中文2,英文1</summary&g ...
随机推荐
- 从零玩转Docker之docker-compose快捷部署中间件-dockercompose2
title: 从零玩转Docker之docker-compose快捷部署中间件 date: 2023-04-04 17:35:18.035 updated: 2023-05-13 23:08:09.5 ...
- C语言之检验三边能否构成三角形
要求: 编写程序检验由三边能否构成三角形,检验方法是任意两边和均要大于第三边. 输出格式:若结果可以构成,输出YES,否则输出ERROR DATA 其实很简单,运用与逻辑运算符&&判断 ...
- ubuntu 之 安装mysql8
安装 1 wget https://dev.mysql.com/get/mysql-apt-config_0.8.12-1_all.deb 2 sudo apt-get update sudo apt ...
- static、final、private是否可以修饰抽象方法?
1.static和abstract:是不能共存的.static是为了方便调用,abstract是为了给子类重写,没有方法体. 2.final和abstract:是互相冲突的,final修饰的方法不能重 ...
- SpringBoot基本知识
SpringBoot基本知识 一.简介 1.spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置, ...
- three.js中的矩阵计算
目录 1. 概述 2. 详论 2.1. 行主序与列主序列 2.2. 矩阵乘法 3. 参考 1. 概述 three.js中自带了矩阵运算库,不过在使用的过程中总是容易混淆.不知道是行主序还是列主序,前乘 ...
- Python函数加async,但没有加await可以异步吗
在Python中,如果一个函数被标记为async,这意味着它是一个异步函数.但是,仅仅因为一个函数被标记为异步并不意味着它会自动异步执行.为了使异步函数真正异步,你需要在函数内部使用await关键 ...
- 快速上手Linux核心命令(二):关机、重启
@ 目录 前言 一.在命令行下查看命令帮助 man 命令 --help 命令 info命令 二.Linux关机.重启 shutdown reboot.halt.poweroff 前言 从这篇开始,我们 ...
- 实战案例丨GaussDB for DWS如何识别坏味道的SQL
摘要:SQL中的坏味道,你知道吗? SQL语言是关系型数据库(RDB)的标准语言,其作用是将使用者的意图翻译成数据库能够理解的语言来执行.人类之间进行交流时,同样的意思用不同的措辞会产生不同的效果. ...
- 海量监控数据处理如何做,看华为云SRE案例分享
摘要:openGemini的设计和优化都是根据时序数据特点而来,在面对海量运维监控数据处理需求时,openGemini显然更加有针对性. IT运维诞生于最早的信息化时代.在信息化时代,企业的信息化系统 ...
