JAVA开发规范
前言
本规范的目的是提升代码质量,提升团队协作效率,规范中出现的强制,推荐,参考含义如下:
【强制】:必须严格遵守,如有特殊情况,需架构委员会评审报备。
【推荐】:没特殊情况必须遵守,在开发组长允许下可以不遵守。
【参考】:可以参考,不做严格要求。
后台开发规范
1.1 命名规范
-
【强制】驼峰式命名,其他不允许,常量除外。
-
【强制】拼音和英文混合不允许。
正例: alibaba / taobao / youku / hangzhou 等国际通用的名称,可视同英文。 反例: DaZhePromotion [ 打折 ] / getPingfenByName() [ 评分 ]
-
【强制】常量命名大写,单词以下划线隔开,语义尽量表达完整,比如MAX就语义不明确。
正例: MAX _STOCK _COUNT 反例: MAX _COUNT
-
【强制】抽象类使用Abstract开头或者Base结尾,异常类以Exception结尾, 测试类命名以它要测试的类的名称开始,以 Test 结尾。
-
【强制】除非业界通用缩写,否则不允许单词缩写。
反例: AbstractClass “缩写”命名成 AbsClass;condition “缩写”命名成 condi ,此类随意缩写严重降低了代码的可阅读性。
-
【推荐】工具类以Utils结尾,帮助类以Helper结尾,帮助类跟工具类的区别在于帮助类是方便业务逻辑使用的,工具类是更通用的。
正例: 应用工具类包名为 com . yujiahui . common . util 、类名为 MessageUtils( 此规则参考spring 的框架结构 )
-
【推荐】枚举类使用Enum结尾。
-
【推荐】如果模块、接口、类、方法使用了设计模式,在命名时体现出具体模式。
说明:将设计模式体现在名字中,有利于阅读者快速理解架构设计理念。 正例: public class OrderFactory; public class LoginProxy; public class ResourceObserver;
-
【参考】分层命名规范
1. DTO命名规范,如果DTO是命令,则Cmd结尾,如果是查询,Query结尾,如果是view object,VO结尾,其他无法归类的DTO结尾。 2. Service层以Service结尾,Dao层以Dao结尾。方法获取单个对象以get开头,获取多个对象以list开头,获取数量已count开头。 插入以create开头,更新以update开头,删除以delete开头 3. 领域层工厂以Factory结尾,领域服务建议以DomainService结尾,实体和值对象不需要后缀,是什么名称就什么名称,比如订单实体就叫Order 4. 领域模型层命名尽量与数据表一致,比如表order_detail,命名为OrderDetail,如果表有统一前缀,前缀是否体现到模型对象名上在一个项目内统一。
-
【推荐】实体里面有些布尔方法如果用is开头容易被框架判断为属性,建议都用iz开头,比如izEasy。
1.2 常量规范
-
【强制】魔鬼数字不允许。
-
【强制】long 或者 Long 初始赋值时,使用大写的 L ,不能是小写的 l ,小写容易跟数字 1 混淆,造成误解。
说明: Long a = 2 l; 写的是数字的 21,还是 Long 型的 2?。
-
【推荐】不要在一个类里面维护所有常量,比如领域模型的常量可以放到领域模型里面,也可以另外建立一个常量类,常量类以Constants结尾
正例:缓存相关常量放在类 CacheConstants 下 ; 系统配置相关常量放在类 ConfigConstants 下
-
【推荐】常量类共享应该按层次放置,层次分为:跨应用共享,应用内共享,模块内共享,类内共享。跨应用共享的常量类放置在一个jar的constant包下,应用内共享的常量类放置下通用模块下的constant包下,模块内共享的常量类放置在本模块的constant包下。
反例:易懂变量也要统一定义成应用内共享常量,两位攻城师在两个类中分别定义了表示“是”的变量: 类 A 中: public static final String YES = " yes " ; 类 B 中: public static final String YES = " y " ; A . YES . equals(B . YES) ,预期是 true ,但实际返回为 false ,导致线上问题。
1.3 格式规范
- 【强制】第一个大括号不换行,单行字符120个,其他采用IDE默认格式。
- 【推荐】不同业务逻辑或者不同语义的代码之间需要有空行。
- 【强制】IDE设置文件编码为UTF-8。
- 【强制】一行不允许定义多个变量。
1.4 Java规范
-
【强制】所有覆写的方法都必须加上@Override。
-
【推荐】equals方法容易报空指针异常,常量放前面或者使用Objects.equals(jdk7引入)。
正例:" test " .equals(object); 反例: object.equals( " test " );
-
【强制】包装类的相等比较用equals,不能用==。
-
【推荐】基本类型和包装类型的使用标准:
1. pojo类型的属性用包装类型 2. RPC方法的参数和返回值用包装类型 3. 局部变量使用基本类型
-
【强制】领域模型类必须实现toString方法
-
【推荐】类内方法定义的顺序是:公有方法》保护方法》私有方法》getter,setter。
-
【推荐】类的方法的访问控制从严。类的方法只在内部使用必须是private,只对继承类开放,必须是protected,变量跟方法类似。
-
【强制】不要在类里面使用静态变量存储数据,如果需要,使用线程安全的数据结构。
-
【强制】不能在foreach循环中删除集合元素,删除元素使用迭代器。
// 正面案例 Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String item = iterator.next(); if (删除元素的条件) { iterator.remove(); } } // 反面案例 List<String> a = new ArrayList<String>(); list.add("1"); list.add("2"); for (String item : list) { if ("1".equals(item)) { list.remove(item); } }
-
【强制】SimpleDateFormat线程不安全不要定义为static变量。
// 正例:注意线程安全,使用 DateUtils 。亦推荐如下处理: private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() { @ Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd"); } };
-
【推荐】高并发时,考虑锁的性能,尽量用无锁数据结构,能锁区块就不要锁整个方法,能锁对象及不要锁整个类。
-
【强制】有并发修改同一个对象的场景,需要加锁,并发修改的概率大于20%,使用悲观锁,否则使用乐观锁, 乐观锁根据业务场景考虑重试次数。
-
【推荐】有返回值的函数尽量不要修改入参。
-
【推荐】尽量少用else,使用卫语句。比如:if(condition) {return obj;} 其他逻辑; 如果实在if-else多,采用状态模式。
// 正例:超过 3 层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现, public void today() { if (izBusy()) { System.out.println(“change time.”); return; } if (izFree()) { System.out.println(“go to travel.”); return; } return; }
1.5 业务代码规范
-
【强制】方法的参数不允许超过5个。
-
【推荐】参数和返回值不要用Map这种泛化参数。
-
【强制】方法的大括号层级不允许超过4层。
-
【推荐】一个方法只做一件事情,方法不超过30行。
-
【强制】方法不能有副作用,比如查询类方法,不允许改变入参的属性值。
-
【推荐】类不能超过500行。
-
【推荐】不允许大量重复代码。
-
【强制】批量操作必须分组,比如批量插入一千条数据,分为500一组。
正例:List groups = Lists.partition(list,500);
-
【强制】业务查询返回数据过多必须分页,比如不能超过5000条返回数据。
-
【推荐】工具类先看项目中是否有提供,不允许随意添加,如果碰到项目中和jar内有同名工具类,优先使用项目中的类,比如StringUtils在多个jar中有,先使用本项目的StringUtils,满足不了要求,再用其他jar的类或者移植方法到本项目的StringUtils。
-
【推荐】重要业务流程必须有业务日志,采用BizLog注解,记录新旧值。
-
【推荐】Service层提供的都是业务逻辑方法,不要放大量查询方法,有多种查询的业务模型抽取出Query类,比如OrderQueryService,也可以采用CQRS模式,命令和查询分离。
-
【强制】业务上存在并发操作的场景,考虑方法的幂等性,或者使用乐观锁。
-
【推荐】时刻进行代码重构,避免代码腐化,去掉下次再改的心态(潜台词:永不再改)
-
【强制】业务上涉及订单、用户信息、金额等安全敏感数据文件导出并上传阿里云OSS时,必须使用文件服务的
/api/file/uploadPrivate
接口上传到阿里云OSS。 -
【强制】业务逻辑尽量避免跨数据库事务操作,严禁事务中穿插执行不同数据库的sql语句,必要时要考虑失败场景补偿方案和告警机制。
反例: 执行A数据库更新逻辑X 执行B数据库更新逻辑Y 执行A数据库更新逻辑X 执行B数据库更新逻辑Y
1.6 异常规范
- 【推荐】不允许对大段代码进行try-catch。
- 【强制】对于有核心功能的死循环线程必须try-catch整个循环体,防止任何异常导致循环线程退出,如果有性能问题,可以酌情优化
- 【推荐】不允许捕获异常后不做任何处理,如果不想处理,抛出去。
- 【推荐】方法可能返回null,调用方要做非空判断防止NPE问题。
- 【推荐】避免直接抛RuntimeException,使用业务异常,比如BusinessException,ApplicatinException,DomainException。
1.7 日志规范
- 【推荐】应用的扩展日志文件命名格式 logName.时间.logType.log。logType:日志类型,比如json表示结构化日志,app表示普通日志,logName:日志名称。
- 【推荐】错误日志和业务日志分开。
- 【推荐】异常日志必须包含堆栈信息和现场参数。
- 【强制】严禁输出大量无效日志,比如在大循环中输出日志。
1.8 注释规范
-
【参考】类、类属性、类方法的注释使用 Javadoc 规范,使用/**内容*/格式,避免使用// xxx 方式。
-
【推荐】所有的抽象方法 ( 包括接口中的方法 ) 必须要用 Javadoc 注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能。
说明:对子类的实现要求,或者调用注意事项,请一并说明。
-
【推荐】所有的枚举类型字段要有注释,说明每个数据项的用途。
-
【推荐】代码修改的同时,注释也要进行相应的修改,尤其是参数、返回值、异常、核心逻辑等的修改。
-
【参考】谨慎注释掉代码。在上方详细说明,而不是简单的注释掉。如果无用,则删除。
说明:代码被注释掉有两种可能性:
1. 后续会恢复此段代码逻辑。
2. 永久不用。前者如果没有备注信息,难以知晓注释动机。后者建议直接删掉 ( 代码仓库保存了历史代码 ) 。
-
【参考】对于注释的要求:第一、能够准确反应设计思想和代码逻辑 ; 第二、能够描述业务含义,使别的程序员能够迅速了解到代码背后的信息。完全没有注释的大段代码对于阅读者形同天书,注释是给自己看的,即使隔很长时间,也能清晰理解当时的思路 ; 注释也是给继任者看的,使其能够快速接替自己的工作。
-
【参考】好的命名、代码结构是自解释的,注释力求精简准确、表达到位。避免出现注释的一个极端:过多过滥的注释,代码的逻辑一旦修改,修改注释是相当大的负担。
// 反例 put elephant into fridge
put(elephant, fridge);
方法名 put ,加上两个有意义的变量名 elephant 和 fridge ,已经说明了这是在干什么,语义清晰的代码不需要额外的注释。
-
【推荐】及时清理不再使用的代码段或配置信息。
说明:对于垃圾代码或过时配置,坚决清理干净,避免程序过度臃肿,代码冗余。 正例:对于暂时被注释掉,后续可能恢复使用的代码片断,在注释代码上方,统一规定使用三个斜杠(///)来说明注释掉代码的理由。
接口规范
- 【强制】Rest接口返回值必须是BaseResult对象及其子类对象,封装了错误码,错误描述,isSuccess,data信息。data放业务数据。业务错误码自己定义,推荐优先使用英文,避免使用通用错误码,通用错误码参考ExceptionEnum。
比如{code:”0”,msg:”操作成功”,data:{XX}}。
-
【推荐】Rest接口必须标明请求的content_type。比如content_type=applicaton/json
-
【强制】接口提供方必须考虑幂等性,防止重复调用导致严重的业务灾难。
-
【强制】查询接口如果数据量过多,需要分页返回。
-
【推荐】接口必须标明字段的类型,长度,是否必填,文字说明必须准确,反例:person:人员。
-
正例:person:人员编码。
-
【推荐】Rest接口返回值需要综合考虑实际功能、安全和性能需求,精细化按需返回业务数据。
-
比如,移动端接口需要考虑性能问题,要避免返回无效字段;对于中台服务移动端接口返回的多余字段场景,需要业务应用封装处理后再返回给移动端。
PC端接口返回值要求 移动端接口返回值要求 中台服务 满足实际功能、安全即可 满足实际功能、安全即可。性能要求需要业务应用封装处理。 业务应用 满足实际功能、安全即可 除了满足实际功能、安全需求之外,要考虑性能,避免返回无效字段
-
-
【推荐】Feign Api提供方禁止在给下游使用方的jar中引入AutoConfiguration等影响启动的配置类
数据库规范
1. 建表相关规范
- 库名、表名、字段名,使用小写和下划线 _ 分割
- 库名、表名、字段名,不超过12个字符。默认支持64个字符。
- 库名、表名、字段名,见名知意,建议使用名词而不是动词。
- 使用 InnoDB 存储引擎。支持;事务、锁、高并发 性能好。
- 推荐使用 utf8mb4 可以存emoji
- 单表字段数,建议不超过40个
2. 字段相关规范
- 整型定义中不显示设置长度,如使用 INT,而不是INT(4)
- 存储精度浮点数,使用 DECIMAL 替代 FLOAT、DOUBLE
- 所有字段,都要有 Comment 描述
- 所有字段应定义为 NOT NULL
- 超过2038年,用DATETIME存储
- 短数据类型 0~80 选用 TINYINT 存储
- UUID 有全局唯一统一字段属性,适合做同步ES使用。
- IPV4,用无符号 INT 存储
- IPV6,用VARBINARY存储
- JSON MySql 8.x 新增特性
- update_time 设置 on update 更新属性
3. 索引相关规范
-
要求有自增ID作为主键,不要使用随机性较强的 order_id 作为主键,会导致innodb内部page分裂和大量随机I/O,性能下降。
-
单表索引建议控制在5个以内,单索引字段数不超过5个。注意:已有idx(a, b)索引,又有idx(a)索引,可以把idx(a)删了,浪费空间,降低更新、写入性能。* 单个索引中,每个索引记录的长度不能超过64KB
-
利用覆盖索引来进行查询操作,避免回表。另外建组合索引的时候,区分度最高的在最左边。
-
select(count(distinct(字段)))/count(id) = 1
的区分度,更适合建索引。在一些低区分度的字段,例如type、status上建立独立索引几乎没意义,降低更新、写入性能。 -
防止因字段不同造成的隐式转换,导致索引失效。
-
更新频繁的字段,不要建索引。
4. 使用相关规范
-
单表数据量不超过500万行,ibc 文件大小不超过 2G
-
水平分表用取模,日志、报表类,可以用日期
-
单实例表数目小于 500
-
alter表之前,先判断表数据量,对于超过100W行记录的表进行alter table,必须在业务低峰期执行。因为alter table会产生表锁,期间阻塞对于该表的所有写入
-
SELECT语句必须指定具体字段名称,禁止写成
“*”select *
会将不需要读的数据也从MySQL里读出来,造成网卡压力,数据表字段一旦更新,但model层没有来得及更新的话,系统会报错 -
insert语句指定具体字段名称,不要写成 `insert into t1 values(…)``
-
``insert into…values(XX),(XX),(XX)..` 这里XX的值不要超过5000个,值过多会引起主从同步延迟变大。
-
union all
和union
,不要超过5个子句,如果没有去重的需求,使用union all性能更好。 -
in 值列表限制在500以内,例如
select… where userid in(….500个以内…)
,可以减少底层扫描,减轻数据库压力。 -
除静态表或小表(100行以内),DML语句必须有where条件,且尽量使用索引查找
-
生产环境禁止使用 hint,如 sql_no_cache,force index,ignore key,straight join等。 要相信MySQL优化器。hint是用来强制SQL按照某个执行计划来执行,但随着数据量变化我们无法保证自己当初的预判是正确的。
-
where条件里,等号左右字段类型必须一致,否则会造成隐式的类型转化,可能导致无法使用索引
-
生产数据库中强烈不推荐在大表执行全表扫描,查询数据量不要超过表行数的25%,否则可能导致无法使用索引
-
where子句中禁止只使用全模糊的LIKE条件进行查找,如like ‘%abc%’,必须有其他等值或范围查询条件,否则可能导致无法使用索引
-
索引列不要使用函数或表达式,如
where length(name)=10
或where user_id+2=1002
,否则可能导致无法使用索引 -
减少使用or语句 or有可能被 mysq l优化为支持索引,但也要损耗 mysql 的 cpu 性能。可将or语句优化为union,然后在各个where条件上建立索引。如
where a=1 or b=2
优化为where a=1… union …where b=2, key(a),key(b)
某些场景下,也可优化为in
-
分页查询,当limit起点较高时,可先用过滤条件进行过滤。如
select a,b,c from t1 limit 10000,20
; 优化为select a,b,c from t1 where id>10000 limit 20
; -
同表的字段增删、索引增删等,合并成一条DDL语句执行,提高执行效率,减少与数据库的交互。
-
replace into
和insert on duplicate key update
在并发环境下执行都可能产生死锁(后者在5.6版本可能不报错,但数据有可能产生问题),需要catch异常,做事务回滚,具体的锁冲突可以关注next key lock
和insert intention lock
-
TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少,但 TRUNCATE 无事务且不触发 trigger ,有可能造成事故,故不建议在开发代码中使用此语句。说明: TRUNCATE TABLE 在功能上与不带 WHERE 子句的 DELETE 语句相同。
安全规范
接口安全
- 【强制】涉及大批量敏感数据的接口增加限流和内网访问保护
- 【强制】涉及小批量敏感数据的接口增加内网访问保护
- 【强制】所有不宜公开数据都必须添加接口权限
代码安全
- 【强制】新加的jar要经过技术中台组安全检测评估才能使用
- 【强制】敏感字段禁止明文存储,需要使用统一工具类进行加密处理
- 【强制】mybatis中能用#{}时不要用${},#{}能防止SQL注入。禁止SQL拼接不安全参数。
密码安全
- 【强制】所有使用中的业务系统(包括测试环境)密码必须由大写字母+小写字母+数字+特殊字符四种组合,字符数不少于8位。
技术文档的写作规范
- 设计文档需要的核心要素有业务架构 ,应用架构,领域模型(数据架构),技术架构,。
- 业务架构描绘系统的业务流程和功能
- 应用架构描绘系统之间的关系
- 数据架构是指领域模型的关系
- 技术架构描绘系统实现,我们都是比较统一的技术架构,可以省略
Java开发编程军规
一、禁止循环中查询数据库,尽量在循环外一次查询
- 说明
系统性能瓶颈很大一部分都是指向了数据库,而循环中查询数据库非常耗资源。
- 案例
展示少量树结构数据时,循环内查询数据后进行数据组装。导致服务器在测试环境就频繁宕机。
使用java.util.Comparator#compare方法调用数据库查询接口,导致线上性能极低。
二、禁止把redis这种缓存当数据库用
- 说明
缓存无法完全符合事务特性ACID原则,数据存在不可使用的风险比较大。
- 案例
会员数据直接存储到redis缓存中,数据量也比较大,经常会丢数据。
三、禁止循环中创建新线程,尽量使用线程池
四、死循环必须有退出机制
- 说明
死循环中最好有休眠语句存在,另外还要退出机制。
- 案例
订单同步应用请求第三方平台数据时,平台方没有翻页的结束标志,同时代码中没有退出机制直接导致该平台订单同步异常。
五、共享变量必须考虑线程安全
- 说明
尽量避免使用共享变量,无法避免时必须考虑线程安全。
- 案例
微信抽奖功能中,每次中奖都是同一个,原因是对共享变量进行了修改操作,后面的逻辑获取的是脏数据。
六、浮点计算必须使用BigDecimal
- 说明
如果需要精确计算,非要用String来够造BigDecimal不可。
七、批量操作必须考虑合理分组
- 说明
数据量大时须批量操作,而批量操作必须分组,避免一次操作耗时过久导致连锁反应。
- 案例
订单历史迁移数据时,分组为5000,导致数据库删除操作没有走索引。建议分组数量在100~500之间。
八、禁止单点部署
- 说明
增加一台服务器部署可以降低50%的服务不可用风险。
九、禁止大表的全表扫描不加限流
- 说明
全表扫描已经很耗数据库资源了,频繁处理请求不加限流就更雪上加霜。
- 案例
售后问题跟踪单的导出,时间索引没有控制范围,导致全表扫描。导出数据接口没有加限流加剧服务资源消耗。
十、读写分离架构,必须考虑读到过期数据
- 说明
读写分离在业务数据更新写入后再重现读取时会存在延迟问题,导致读到脏数据。
- 案例
A. 双十一开启读写分离,主从同步有延迟,导致业务事件重复发送,原因是读取到历史 脏数据。
B. 会员积分服务创建数据后其他服务应用马上查询,结果是查询到空数据。
十一、事务内有外部调用,必须考虑外部不稳定和性能问题
- 说明
事务本身是很耗资源,极易产生超时的问题,要避免再引入外部不稳定因素。
- 案例
个人中心服务,事务内远程查询美丽分享官的积分,导致性能极低。外部接口调用需要设置超时和最长等待时间。
十二、接口提供方和Xxljob定时任务必须考虑幂等性,防止重复调用导致严重的业务灾难
- 说明
根据墨菲定律,接口重复调用是会必现的线上问题。
- 案例
订单付款接口,幂等逻辑不严谨导致重复付款问题。apollo报表中心由于xxljob一秒内重复调度任务,导致统计数据重复,严重影响管理层的决策判断。
十三、禁止资源操作(IO等)后未释放
十四、嵌套事务的默认传播属性是Propagation.REQUIRED,如果需要开启新事务,必须手动设置事务传播属性为Propagation.REQUIRES_NEW。尽量不要使用嵌套事务。
- 说明
使用事务注解或者编程式事务时,需要考虑默认的事务传播属性,根据需要决定是并入同一个事务还是开启新事务。
- 案例
OMS异步操作任务,调用第三方接口时,修改状态为确认中状态,需要先提交事务更新,后面的逻辑操作成功则需要修改为已确认,失败则修改为待审核。当第三方接口没有返回明确的成功或失败时,状态应该保持确认中不变。如果调用接口前不开启新事务,会导致后面回滚的数据有误。
十五、覆写对象的equals()方法时必须同时覆写hashCode()方法
- 说明
equals和hashCode方法是对象在hash容器内高效工作的基础,正确的覆写这两个方法才能保证在hash容器内查找对象的正确性,同时一个好的hashCode方法能大幅提升hash容器效率。
十六、禁止含事务的循环内加线程同步锁
- 说明
循环上层包含事务,使用synchronized锁,会导致MySQL事务锁和JVM同步锁互相等待死锁问题。
- 案例
@Transactional(rollbackFor = Exception.class)
public void storeData(List<Order> orderList) {
/**
order_id = {1,2,3}
线程A更新order_id为1后进入下一轮循环,事务锁还未释放,同步锁需要重新获取。
同时线程B已获取同步锁,需要更新order_id=1的事务操作。结果就是线程A等待线程B持有的
JVM同步锁,线程B等待线程A持有的事务锁。
*/
for(Order order : orderList) {
synchronized (LOCK) {
updateOrderId(order);
}
}
}
十七、使用线程池时,必须设置合理的大小,禁止不加限制动态批量创建线程
- 说明
不加限制的批量创建线程会抢占大量系统的资源,引发OOM等连锁异常,最终导致宕机
- 案例
将new MapReduce<>(xxx)创建线程池的代码放在API接口实现方法中没有加其他限制,导致引发OOM宕机,中间触发了Redis连接超时、Kafka重复消费等异常
十八、所有公共代码(比如api包、通用工具类)或公共服务(中台服务、业务应用自身服务)的改动,必须考虑向下兼容
- 说明·
对多个系统项目都有依赖的公共代码进行修改时,需要考虑兼容历史逻辑,除非确认所有使用方都能够接受功能修改产生的影响
- 案例
项目A的开发人员将公共jar包中逻辑进行了修改(该修改需要开启一个新配置才和原逻辑一致),同时deploy jar包进行测试,新配置只在测试环境进行了操作。依赖了公共jar包的项目B这时进行线上发版,但是没有进行配置(而且也不知道有这个配置),导致线上事故。
十九、禁止在新建表或者增加修改表字段时设置字符集和排序规则
- 说明·
字符集和排序规则后期修改需要耗费巨大的资源,影响业务稳定性,为了保持schema-表-表字段三者的字符集和排序规则一致,禁止在新建表或者增加修改表字段时设置字符集和排序规则。
- 案例
A项目的某一个表的字段设置了字符集和排序规则,导致与表-schema的排序规则不一致,在联合查询时这个表作为关联字段,报关联字段排序规则不一致的错误,无法进行关联查询,只能修改,如果是一张大表修改会非常耗时,占用大量的io会影响业务。
二十、新建表或者增加修改表字段时使用TEXT/BLOD字段需要评估必要性
- 说明·
TEXT/BLOD的大字段会产生磁盘临时表,而且不能使用全文索引,各种操作的代价都非常高昂,在业务中最好不要使用,如果实在是要使用,也要独立出一张表专门用于存储,不得跟业务表中使用。
- 案例
A项目前期的一张表中使用了一个TEXT存储json大字段,导致这张表占用了600多G的空间,其中那一个大字段就占用90%的表空间,后续的查询,迁移,碎片整理都非常的耗资源。