乐观锁是一种并发控制的方法,它假设在大多数情况下数据在并发访问时不会发生冲突,在更新数据时不会进行强制的排他性锁定,只有在提交更新时才会检查数据是否被其他事务修改过。
一、工作原理
- 版本号机制
- 通常在数据库表中添加一个版本号字段。
- 当一个事务读取数据时,会记录下数据的当前版本号。
- 当事务要更新数据时,会再次读取数据,并检查版本号是否与之前读取时一致。
- 如果版本号一致,说明数据没有被其他事务修改,事务可以进行更新,并将版本号加 1。
- 如果版本号不一致,说明数据在读取后被其他事务修改过,当前事务的更新操作失败,通常会进行重试或者提示用户。
- 时间戳机制
- 类似于版本号机制,只是用时间戳来代替版本号。
- 事务读取数据时记录下当前的时间戳。
- 更新时检查时间戳是否发生变化来判断数据是否被修改。
二、适用场景
-
读多写少的场景
- 当系统中数据的读取操作远远多于写入操作时,乐观锁非常适用。
- 因为乐观锁不会在读取数据时进行加锁操作,所以不会影响读操作的性能,同时也能较好地处理写操作的冲突。
- 例如一个商品库存查询系统,用户主要是查询商品库存信息,偶尔会有管理员修改库存数量,这种情况下乐观锁可以提供高效的并发控制。
-
冲突概率较低的场景
- 如果数据在并发环境下发生冲突修改的概率较低,乐观锁可以减少不必要的锁开销。
- 比如一个用户信息管理系统,用户的基本信息通常不会频繁被多个用户同时修改,此时使用乐观锁可以在保证数据一致性的前提下提高系统性能。
三、与悲观锁的比较
- 锁的机制
- 悲观锁:悲观锁在操作数据之前就假定会有冲突发生,所以会先获取排他性的锁(如行锁、表锁等),确保在事务执行过程中数据不会被其他事务修改。
- 乐观锁:乐观锁则是在提交更新时才去检查数据是否有冲突,在读取和修改数据的过程中不进行加锁操作。
- 性能影响
- 悲观锁:由于在操作前就加锁,会导致其他事务在等待锁释放时被阻塞,特别是在高并发环境下,如果大量事务等待锁,会导致系统性能下降,甚至出现死锁的情况。
- 乐观锁:因为没有在操作过程中加锁,所以不会出现阻塞的情况,在冲突概率较低的情况下可以大大提高系统的并发性能。但是在冲突频繁发生时,由于需要不断地重试或者进行其他冲突处理操作,可能会导致性能下降。
- 适用场景的差异
- 悲观锁:适用于写多读少或者对数据一致性要求非常高、冲突可能性较大的场景,例如银行系统中的账户资金操作等。
- 乐观锁:更适用于读多写少、冲突概率较低的场景,如前面提到的商品库存查询和用户信息管理系统等。