我们 **给出一种兼顾并发、性能和数据一致性的交易实现 **。这个实现在隔离级别为 RC 和 RR 时,都是安全的
有个问题,既然「不可重复读」会读取到不一样的结果,那么如果在事务中间态对数据进行了更新,是否会出现问题呢
我们 **给出一种兼顾并发、性能和数据一致性的交易实现 **。这个实现在隔离级别为 RC 和 RR 时,都是安全的
有个问题,既然「不可重复读」会读取到不一样的结果,那么如果在事务中间态对数据进行了更新,是否会出现问题呢
在同一个事务内两次读取同一条数据,读到的结果可能会不一样,这就是「不可重复读」
事务 A 读取字段 amount 为 100,此时另一个事务 B 修改 amount 为 200,事务 A 再次读取,结果是 200。「不可重复读」的意思是对于同一事务内的数据不可重复读取,因为他的隔离级别是会被其他事务修改
第一种 RU 级别,实际上就是完全不隔离。每个进行中事务的中间状态,对其他事务都是可见的,所以有可能会出现「脏读」。我们上一个小节充值的例子中,读到了 888 这条流水,但余额还是转账之前的 100 元,这种情况就是脏读
脏读: 事务处在中间状态被读取了数据
事务的 ACID 四个基本特性
设计账户流水的原则 * 流水记录只能新增 * 流水号必须是递增的
如果是考虑并发问题,可以考虑将将 redis 做主要的存储,然后异步写入 mysql 中,做一些分析的时候,就从 mysql 中查询
比如加购统计功能,每次加购就记录进 MySQL 中,也能实现后期统计的功能
缓存的使用场景是 读多写少,而且是 用户自己访问自己的,明显的是写多读少的场景,不太适合了
缓存使用原则
这种缓存更新的策略,称为 Cache Aside,是最简单实用的一种缓存更新策略,适用范围也最广泛。如果你要缓存数据,没有什么特殊的情况,首先就应该考虑使用这个策略
正常情况下,订单中的快递单号会先更新成 666,再更新成 888,这是没问题的。那不正常情况呢?666 请求到了,单号更新成 666,然后 888 请求到了,单号又更新成 888,但是 666 更新成功的响应丢了,调用方没收到成功响应,自动重试,再次发起 666 请求,单号又被更新成 666 了,这数据显然就错了。这就是非常有名的 ABA 问题
用数据库乐观锁机制解决。每次查询订单返回一个 version,更新订单时,带上这个 version 到数据库比对
我们给订单系统增加一个 「生成订单号」的服务,这个服务没有参数,返回值就是一个新的、全局唯一的订单号。在用户进入创建订单的页面时,前端页面先调用这个生成订单号服务得到一个订单号,在用户提交订单的时候,在创建订单的请求中带着这个订单号
茅塞顿开,由于在下单的业务流程中,创建订单和提交订单几乎不可能同时执行,所以可以在创建订单时就给前端生成一个订单号,这样提交过来的订单就一定是这个订单号,无论发送多少次请求,数据库的唯一约束都会帮我们保证幂等性
一个有效减少系统复杂度的设计经验。那就是,如果系统业务是复杂而多变的,尽量识别出这部分复杂业务的边界,将复杂封禁在一个模块的内部,避免这种复杂度扩散到整个系统中去
一个庞大而复杂的系统是无法长期维护的,必须将其拆成更小的部分,才能分而治之,无论是代码还是公司
只对尚未推送或分享给别人的本地修改执行rebase操作清理历史,从不对已推送至别处的提交执行rebase操作
只从远程分支 rebase 到本地分支,如 master 分支 rebase 到 topic brach。 从本地分支合并到远程分支用 merge
现在的职业场景不是一条条管道,而是一个巨大、无比复杂、快速变换着的科学实验室
是一个巨大的网络。每个职业并不是完全孤立的,新的机会往往都在那些多个学科的交叉点上
当你把职业看成一条管道,做出正确选择就好像参与一场赌注很高的赌博,让选择困难症的程度瞬间爆炸。对于完美主义者来说,这简直是件痛彻全身的事情。
这很像我做一些事情,比如买床单被单之类的,在我知道有「支数」这种东西却又不完全了解它的时候,为了避免做出错误选项而失去正确选项,我会倾向于不做选择,这同时也是放弃了所有的机会。而实际上你不该想这么多,just do it
取决于不同的职业,社交技能可能也会很重要。在很多职业中,招人喜欢的人比不招人喜欢的人要有很大的优势,而那些热衷于社交的人,自然而然会花上更多时间来建立更多的人际关系
「社交」的重要性仅次于「元技能」
职业是很复杂的游戏,每个人开场的时候几乎都是菜鸟,而“厨师”们是会通过一个闭环来持续提高的:
这个闭环就是[[刻意练习]]
今天的职业场景有成千上万种选项组成,有一些有几十年的历史,有一些可能是因为三个月前的某种新技术诞生而出现的。如果你有一种想从事的职业,但是市场上还看不到,你还可以自己创造一个出来
根据你的职业场景画像来确定你要做什么职业,而不是根据职业来决定你的职业场景画像(厨师思维和厨子思维)
剩下来的大部分欲望会被放置在底层架子上。把你真实的一部分放在底层架子上,实际上就是你在告诉自己“我知道你想要这些东西,但是现在有一些更重要的事情需要关注。我保证,不久后,如果我获得了更多的信息,或者我想法变了,我会把你升级到高一点的架子上。”
想要住在更舒服的房子、想开更好的车等等
最高优先级的内心驱动力进入了“最特别的没有商量余地碗”(最特碗)里面。最特碗装载的是你最重要的那些欲望,你无论怎样都想要这些欲望被满足,如果有必要,你可以抛弃其它所有的欲望
我目前"最特碗"中装着的: 时间上的自由。我想要和现在一样,有着自己可支配的时间,不必早起到公司打卡,不必和其他所有人一样挤同一趟地铁
中间的架子是留给那些你愿意接受的,不怎么高尚的欲望的。它们应该获得你的一些关注,如果你忽视它们,它们很可能会毁掉你的生活
社交欲望、性欲望等
最上层架子的位置,是能够驱动你的职业选择的欲望
对折腾电子工具的热衷,让我希望从事计算机相关的职业
重新绘制地图 1. 画出"想要"框 * 想要框包含所有你脑子里想达成的欲望,不论是否可行,类似于头脑风暴 2. 画出"现实"框 * "现实"框包含所有你所能够,或者你有潜力能够达到的职业
“第一性原理思维”(厨师)就是像科学家一样思考——把核心事实和观察拿出来,从它们的碰撞中得出结论。就好像一个厨师尝试各种食材来创造美食一样。只要坚持这样做,厨师最后肯定会创造出新菜谱。而“类比思维”(厨子),就是你看着事情已经有的样子,然后模仿一遍。模仿的过程可能会加入一点个人元素,就好像一个厨子照着一个现成的菜谱做饭。
虽然"厨师"比"厨子"的主观能动性强,但要成为一个"厨师"就必须先成为一个"厨子"
虽然我们不知道未来会变成什么样,但可以更好地应对这个事实。Morgan Housel 在 The Psychology of Money 提了两个很好的建议。 第一,避免极端。很多人说他们后悔年轻时都在为事业拼搏而忽略了家人,这是因为过于极端。无论在工作的哪个阶段,每年存一些钱,留一些空闲时间,花一些时间陪伴家人。 第二,接受和允许自己改变主意。过去的事情都是沉没成本,如果一味让跟现在的自己完全不同的过去的自己来决定现在,无异于让一个陌生人来给我们做决定,越快放下越好。
接上文
很重要的是要反思和抽象。就像有些学霸做一道题就跟做了十道题一样,如果你知道从初级的职位升职到中级没有你想象的感觉那么好,你就应该知道再往上走给你的感觉也差不多;如果你知道住了一周的高档酒店也会让人厌倦,你就不会无止境地追求奢华;如果你发现金钱买来的快乐还不如和朋友谈一次心,你就知道什么对你来说更重要。
反思和抽象: 学会管中窥豹,根据[[二八定律]],你只需要参与 20%,就能抽象出 80% 的参考信息(如读一本书、看一部剧)
如果我们没有足够的经历,我们很难清楚自己真正想要什么
估算自己的试错成本,如果成本低就多去尝试,例如在上学时、年轻单身不需要承担家庭负担时,这种时候多去尝试,即使失败也不会有太多损失
当我们无意识与人比较的时候,停下来,问问自己,我们愿意和那个人交换所有的吗?不仅是好的东西,还包括他们的痛苦和烦恼
大多数人只能看到别人光鲜的表面,却并不知道这背后藏着怎样的痛苦和烦恼,原因在于许多人看待一件事物并不是立体的,他们往往在被动地接收着外界主动释放出的信息
伊贝拉说,人们就想要一个答案,所以这样的思维框架才卖得好
现如今互联网上各种[[贩卖焦虑]]的营销手段,就是通过营造出"你买了我们的课程,就得到了答案"给与用户一种自我欺骗的安心感
The challenge of modern work is how to create systems that free up attention, instead of consuming more of it.
Projects have become non-linear – not simply a sum of the time and dollars spent on them, but complex emergent phenomena we can barely understand or control. Because understanding them takes just as many units of attention as acting on them, it makes more sense to plunge in with exploratory actions, instead of trying to predict what will happen in advance.
和[[一致性原理]]的"了解事物本质,然后通过[[演绎法]]去预测发展"的观点相反
Telling only what to do is a huge mistake. You should spend at least some of your time to tell why you do what you do and why it is important.
不只是告诉团队怎么做,还要告诉团队为什么。这样会让其他成员有一种使命感,让他们觉得"我正在做一件有意义的事",这样他们在完成工作时会产生成就感
社交酬赏指的是发表文章、分享之后,收到点赞、评论、交流
从写书评开始,建立写文章的习惯。慢慢体验创造产生的[[多巴胺]]
检视阅读。一种快速阅读的方式,之所以快,是因为阅读的内容少。只阅读封面、序、目录、后记,以及自己非常感兴趣的部分段落。这样即可对书的整体内容、框架有一定的了解,以此判断这本书是否值得阅读
挑书的一种办法,但同时要小心回音壁效应,也许作者的写作风格不适合你,但内容确实有用。这时候可以通过豆瓣的评分、讨论区来判断是否值得一读。如果读者对书的评价比较两极分化,也可以读,但优先级放后。《囚徒健身》就是不管在内容还是豆瓣评分都较高的书,但读完了才知道书中健身方法根本毫无逻辑
最高学习效率是15.87%,即15%的陌生知识,加上85%的熟悉知识
N + 1 学习模式
其中 name 表示该初始化器的参数,self.name 表示该实体中的 name 所对应的数值
self 类比 Java 的 this
在 Swift 语言中,开发者可以同时使用 willSet 和 didSet 两个触发器的触发时机。willSet 中的代码会在 livesRemaining 即将被修改、但还没有被修改时运行;didSet 会在 livesRemaining 的值已经被修改后运行
类比 Java 的 AOP
如下图所示,Swift 提供了便捷参数名 newValue 以供使用,此处的 newValue 指的是被赋的值。如下图的 playerWang.isPlayerOutOfLives = true,则 newValue 也为真,这里的 newValue 代表的就是被赋的值 true。在 set 语句 if newValue { livesRemaining = 0 } 中,如果 isPlayerOutOfLives 的 newValue 为真,则设置基础属性 livesRemaining 为 0。预计算属性的 get 和 set 在此处起到了读取及修改其它属性的作用,其中 get 负责读取预计算属性的值,set 则代表赋值
预计算属性的 set 语句相当于从「果」导致「因」, 因为「玩家死亡」的结果已经产生, 所以「玩家生命值为0」必定为真
定义结构
语法 struct
在 Swift 语言中,结构 struct 就好像这个模具,开发者负责定义 Define 模具所具备的属性 Property 及功能 Method
抽象 abstract
使用模具生产产品,叫做创建一个实体 Instance
构建对象实例
此时的参数 Argument 代表该参数的真实数值
形参 & 实参
let isRainingOutside: Bool = true
var variable = value // 没有指定变量类型(弱类型) var variable:type = value // 指定变量类型(强类型)