buguge - Keep it simple,stupid

知识就是力量,但更重要的,是运用知识的能力why buguge?

导航

不能坐视了!Oracle数据库varchar2字段扩容,每月总有那么一两次。----- 优秀的程序应总是尽可能地规避问题

Oracle数据库varchar2字段扩容-始末

今天,有后端小伙伴提了个sql工单。对我司服务商系统Oracle数据库的一个mer_name字段扩容。

alter table T_MER_SETTLE modify mer_name VARCHAR2(100)

审批前,我查了一下当前这个mer_name字段的长度是 VARCHAR2(64)。

基于对我司客户名称的长度通常不超过64字的了解,我下意识里感到奇怪:莫非存在长度超过64个文字的客户名称?这种情况应该很少吧?什么公司的名字能有这么长呢?

 

然后,我找当事人来询问。他言说,当时开发需求时,看到企业表里的mer_name是varchar2(100),就沿袭使用varchar2了,加上对系统里企业名称长度通常不会超过64个汉字的认识,就把新表的mer_name定义为varchar2(64)。 今天生产环境的告警显示,在向这个T_MER_SETTLE表插入数据时出现“字段值超长”持久化失败的bug,这才得知Oracle的varchar2(64)与mysql的varchar(64)不同,mysql的varchar(64)能存最多64个字符,而Oracle的varchar2(64)则不同。在数据库字符集是UTF-8的情况下,varchar2在存汉字时,是每个汉字占3个字节。也就是说,这个varchar2(64)最多可以存64/3=21个汉字。

 

本着解决问题优先的原则,我审批了sql工单并执行sql。

 

优秀的程序应该尽可能地规避问题

字段扩容,这是我们日常开发中经常遇到的小事。我们服务商系统类似对varchar2字段扩容的案例,几乎每月都发生。那么,针对这个字段扩容,大家有没有琢磨过,我们如何在开发时就能规避呢?

优秀的程序应该尽可能地规避问题。我们来复盘一下这个事情。

有必要先说明一个情况,我司绝大多数系统以mysql数据库为主,服务商系统是其中唯一一个使用Oracle数据库的小众系统。并且,服务商系统的日常维护或需求迭代较少,由我们技术团队中的三个同学抽一部分精力兼管。 因此,大家对Oracle数据库了解得并不多,相比mysql,就少多了。

好,继续来复盘。
开发人员不了解varchar2这个技术点,凭着mysql数据库经验和对业务的了解,定义了  mer_name VARCHAR2(64) 。
我在审批时,也不了解varcahr2这个技术点,就去反问开发同学。同样,其他同学,也未必清楚Oracle的varchar2这个数据类型的细节。

 

那么,如何规避呢?

无药可救了吗?

不!

我们事后了解到,Oracle的nvarchar2不区分字符类型,它将汉字、全角符号与数字、字母、半角符号等均视为一个字符。也就是说,nvarchar2(64)表示可存最大64个字符。注意这里不是字节,而是字符。 包括 数字、字母、符号、以及汉字。同时,在存储含有文字的字段时,Oracle开发规范里建议使用nvarchar2取代varchar2。

因此,我们可以做什么?

将数据库里的mer_name的数据类型全部改为nvarchar2,以及其他的这种varchar2字段类型使用不当的字段。

这以后,服务商系统再有迭代开发时,开发者CV时,就不会(或很少)再有varchar2的mer_name了,乐观一点讲,再出现因varchar2数据类型使用不当而导致“字段值超长”持久化失败的bug就会扼杀在摇篮里。

 

【附】Oracle数据类型varchar2与nvarchar2

  1. varchar - Oracle不建议使用varchar类型(我在DBeaver中新建varchar字段时自动建成了varchar2,无论是所见即所得的操作方式,还是执行DDL方式)
  2. varchar2 - varchar2(20) 表示可存最大20个字节长度的字符串。 数字/字母/半角符号 占一个字节。 对于全角符号或汉字,则要看字符集,GBK的话,一个汉字占2个字节;UTF-8的话,一个汉字占3个字节。
  3. nvarchar - Oracle中没有nvarchar这个数据类型
  4. nvarchar2 - nvarchar2(20) 表示可存最大20个字符。注意这里不是字节了,而是字符。 包括 数字、字母、符号、以及汉字。每个字符占2个字节存储。
 
  • varchar2是Oracle提供的特定数据类型,Oracle可以保证varchar2在任何版本中该数据类型都可以向上或向下兼容。
  • nvarchar2虽然更占空间,但是它有更好的兼容性。尤其是当字段包含汉字的情况下,推荐使用nvarchar2。  - - - - - - - - 我们服务商系统Oracle数据库里,对于mer_name等包含汉字的字段,大家往往沿袭使用varchar2(100甚至更大),我们在新建表里涉及到这个字段时,有开发者会误以为Oracle的varchar2与mysql里的varchar相同,我们mysql应用里约定mer_name是varchar(32) ,就在Oracle库里定义成了 varchar2(32) ,结果,服务商系统在生产运行过程中,出现插入mer_name因字段值超长而持久化数据库失败。 - - - - - - - - 优秀的程序应总是尽可能地规避问题。因此,以后在服务商系统里,当定义包含汉字的字段时,使用 nvarchar2,而非 varchar2。 因此,在服务商系统作为我司系统的小众系统的背景下,Oracle的技术特性我们不一一晓知是可以理解和接受的。而如何在不一一晓知这些技术特性的情况下,能够规避这些技术特性带来的bug,需要我们引起思考和实践摸索。
 

 【附】字段值超长,程序异常截图↓

 

posted on 2024-01-29 20:55  buguge  阅读(148)  评论(0编辑  收藏  举报