1 什么是消息的幂等性
如果同一个消息,因为各种原因,不慎被消费了多次(例如多次点按按钮),和只消费一次得到的数据是相同的。就可以说保持了幂等性。
如果我们不人为保证消息的幂等性,数据就会出错。可以通过乐观锁、悲观锁等方式保证消息的等幂性。
2 乐观锁与悲观锁
乐观锁是一种教宽松的锁机制,在线程进行数据更新之前对当前的数据版本进行比对,如果版本相同则允许进行操作。
悲观锁是一种较严格的锁机制,即悲观的认为每个线程在更新数据的时候都会被其他线程修改数据。为了防止这种情况,在一个线程需要操作数据时,先取锁再操作。
3 乐观锁
3.1 乐观锁之CAS
CAS即CompareAndSwap(比较和交换)。
当希望更新一条数据的时候,将原始的数据也一起取出来。最终进行更新的时候,将取出的原始数据和现在数据库中的数据进行比较,如果相同,则进行操作。
例如:数据库中有一条用户信息的用户名为Tom,需要变更为Tony。生产者在生产消息时,消息中就携带着原始的用户名Tom。当消费者进行更新操作前,将Tom和当前数据库中的用户名进行比较,
相同才进行更新操作。
3.2 CAS的缺点
虽然能够实现乐观锁,但CAS方式并不是完美的,也存在一些缺点。
ABA问题
还是以修改用户名为例,理想中的CAS流程是这样的:
而实际的流程却可能是这样的:
在取出数据与更新数据的间隔之间,数据已经被修改过了。
现实中的类似的情况就是,保险柜里有10W块钱。财务人员监守自盗,拿着10W元去买彩票。中奖之后又往保险柜里放了10W元。虽然前后金额没有变化,但却是存在安全隐患的。
3.3 乐观锁之版本号
版本号机制本质还是CAS,但通过给变量携带一个版本号,规避了ABA问题。
版本号可以使用一个自增的数字,也可以使用时间戳。
4 悲观锁
悲观锁主要依靠关系型数据库的锁机制。悲观锁又分为共享锁和排它锁。
4.1 共享锁
共享锁又称为读锁。多个事务可以共享一个读锁,对数据进行读取。
4.2 排它锁
排它锁又称为写锁。只有一个事务可以获取到写锁。其他事务要等待获取到写锁才可以对数据进行更新操作。