查看原文
其他

CRUD 很简单?你的代码根本不健壮!

破产码农 InsideMySQL 2022-10-13
点击卡片,关注 InsideMySQL

姜老师,为什么你写的文章都在说我们是错的?

分库分表设计是错的!(网上所谓的大厂分库分表,都是错的!

加索引的方法是错的!(10亿条记录的表,如何做 DDL 操作?

就连关闭 MySQL 数据库,这么简单的操作,都是错的!(如何正确地关闭 MySQL 数据库?99%的 DBA 都是错的!

今天又要跟我们说连最最基本的 CRUD 操作也都是错的?

你这是在 PUA 我们!

不好意思,发错图了,应该是:

嗯,我明白小可爱们很生气,越是深耕数据库领域的,越是气愤,就想找机会回怼姜老师。

打开微博,大V们各种滔滔不绝,指点江山。仔细分析,说的全是废话。任泽平去年告诉你房产税要来了,房价要大跌。今年又说,通胀时代,房子是最好的资产。

打开CSDN,老盖告诉你 Oracle 是最好的,开源数据库还有很长的路要走。德哥告诉你 PostgreSQL 是未来,108种应用场景要学会。TiDB 天天打广告,自己是分布式数据库的未来,XX公司,甚至国外公司都用了我们的产品。

话都不假,但全是废话。

当今之世,真正的专家又有多少?能掏心掏肺无私分享的,又有几人?

看看姜老师告诉你们的是什么呢?

学好 MySQL 年薪 50W 轻轻松松!35岁码农不是瓶颈,不会失业!

随便拿着姜老师分享的文章去提升你们生产系统数据库的稳定性,职级都能至少上升2级。

PUA?你见过没有任何好处,倒贴钱的 PUA 么?

姜老师是带你飞的!传递的是正能量。

好了,今天就来看最基本的数据库操作 CRUD 。




MySQL 数据库的 CRUD 是通过各语言的 MySQL Connector 完成的。

这是每个程序员梦开始的地方,但也是错误开始的地方。

请问下面的代码有什么问题?

代码逻辑很简单,往一张表插入一条数据。

在真实的业务代码里,稍微会有变化的是不会每次创建一个短链接,而是使用线程池。另一方面,SQL语句会进行 PrepareStatement 格式化,避免 SQL 注入。

但这些都不是今天讨论的重点,重点是无论你是否使用线程池,PS 去格式化 SQL 语句,上述的代码都是不健壮的

因此,今天的重点是,如何进行健壮的数据库编程。

上述代码看似有了try、except这样的健壮逻辑,但是真实世界是非常复杂的。

try、except逻辑只能保证程序在单机运行是健壮的,因为单机运行每个指令都是原子的。

数据库真实的世界是怎样的?

真实的数据库世界是有高可用的,也就是说至少会是一主一从的架构,然后通过半同步复制保证主从数据的一致性。

在核心业务场景,通常会通过下面的设置确保主从数据的一致性:

plugin-load = "semisync_master.so;semisync_slave.so"rpl_semi_sync_master_enabled = 1rpl_semi_sync_slave_enabled = 1rpl_semi_sync_master_timeout = 999999999999

上述配置表示启动半同步插件,并将等待 ACK 时间设的无限大,这样能保证主从数据的严格一致。

若发生任何问题,通过外部 HA 组件进行 failover 的切换。

当然,用户也可以用 MGR(MySQL Group Replication) ,使用 Paxos 协议复制数据,从而保证数据一致性。切换通过 MGR 内置的 Paxos 协议进行选主。

什么?你的生产数据库环境没有类似半同步或Paxos复制机制?那请你尽快离开。

有了半同步复制,那么再看上面的代码,你会发现原子性被破坏了

因为这时引入了网络,这是一个永远无法确定的环

在复杂多变的网络环境中,每次对于数据库的操作不一定是原子的

也就是说,执行这条SQL,即不显示成功,也不报失败。

对外的表现形式就是数据库卡住了!

这时 DBA 任何操作都是徒劳的,除了进行 kill。但切记是 kill -9。

最简单的一种场景,一主一从,从机宕机,这时上述代码就会卡住,如:

不好意思,手抖了,应该是:

数据库卡住的表现是什么呢?通过命令 SHOW PROCESSLIST 你会看到类似如下的结果:

即大量的连接发生等待,无法继续执行。

代码中的 except 异常处理逻辑,根本无法处理上述异常

那上层服务的表现是什么呢?

雪崩

因为业务会不断接收新请求,尝试数据库访问,直至服务无法承受为止。

所以,任何健壮的数据库编程,应该都有一个超时时间,这也是 Fail-fast 的设计准则。

因此,对于上述代码,应该在创建连接时增加超时时间,如:

上述代码设置超时为2秒,任何数据库操作超过2秒,则会被 except 捕获,从而跳出永无止境的等待:

其实,不仅仅是数据库操作需要设置超时。任何网络之间的 RPC、HTTP 调用都需要设置超时时间,否则都不是健壮的代码

业务也可以通过超时的错误码进行限流,避免无限制的重试,从而导致业务最终发生雪崩。

最后的最后,若以后发生业务和 DBA 互相扯皮的事情,请这么怼他:你代码写得一点都不健壮,连数据库有异常都不会处理。我奶奶都知道要设置超时!来,我教你



思考题


1. 文章只是给了 Python MySQL Connector 的超时设置,C++、Java、Go等语言该如何设置超时呢?

2. SHOW PROCESSLIST 中显示 waiting ACK 的线程能否被 kill,从而让其他等待的线程继续运行?为什么?

3. 半同步 AFTER_SYNC 和 AFTER_COMMIT 在上述例子中,SHOW PROCESSLIST 结果有何不同?为什么?

4. 今天封面的女郎是谁?

想要知道思考题答案的小伙伴,欢迎加入 IMG 官方社区高端群 
入群请加姜老师个人微信 82946772,并备注:码农入VIP群
IMG 官方社区高端群是订阅制的,不过也就99元/年,权当请姜老师喝杯咖啡。
在会员期间你可以享受到下面的福利:
  • 突破微信群人数500的限制,以后所有高端群小伙伴可以在一起吹水;

  • 提供 IMG 公众号每篇技术文章最后遗留问题的标准答案;

  • 技术圈的江湖八卦,比如某数据库出局某行的原委,某大V被新领导GZ;

  • IMG社区技术嘉年华大会门票5折优惠;

  • 姜老师夫妇的私密分享,包括技术、工作、投资、相亲、移民等热门话题;

  • 会员每邀请新会员入群,可以享受59元的返利(把年费赚回来😄);


往期推荐



10亿条记录的表,如何做 DDL 操作?

网上所谓的大厂分库分表,都是错的!

如何正确地关闭 MySQL 数据库?99%的 DBA 都是错的!

国外教授怒怼国产数据库,但我觉得是他格局小了

ClickHouse 将会是 OLAP 最亮的仔!


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存