【for update】解析 【线程安全】【分布式锁】

1. for update是什么?

for update是一种DML操作级别的行级锁。在结合事务的场景中,事务A对一行数据使用select … for update加锁,其他事务只能查询但不能更新被加锁的数据行,而事务A既可以查询又可以更新该行数据。事务A提交后,其他事务才可以更新该行。

2. for update有哪些应用场景?

2.1.实现线程安全

后端服务运行时,由于存在网络延时,可能会出现上游调用方先后发出两次请求(假设为req_1、req_2)来更新同一行数据的同一个字段的情况。如果后端服务正在处理req_1,在没有拿到req_1的执行结果时直接处理req_2,会产生错误的结果。因此,需要一种线程安全机制来保障只能有一个请求来更新数据。

线程安全机制:

1)在单机版服务上,可以使用synchronized关键字在代码中手动加锁,从而避免多个线程重复更新一行数据,但是synchronized关键字不能解决分布式场景中的并发问题。因为synchronized关键字是在java代码层面中加锁,分布式服务具有多个实例,每台实例不感知其他实例的synchronized关键字。

2)在分布式服务中,可以使用redis实现分布式锁,如果req_1、req_2要申请同一把锁,那么只有后端服务处理完req_1后,req_2才能获取锁进而被服务处理。分布式锁发挥作用的级别在于线程级,服务器接收到一个请求后,会为其分配一个专用的线程,该线程执行某个方法时,会在代码中显式地申请和释放分布式锁(如以自定义分布式锁的注解和切面)。

3)分布式服务中,也可以使用for update实现线程安全。for update发挥作用的级别在于事务级,要比分布式锁更靠近数据底层。结合事务,我们不需要再代码中手动加锁,当处理req_1的线程进入一个事务方法,该方法内使用for update为要更新的数据加锁后,其他事务只能查询无法更新被锁的数据。

2.2.主从数据库结构下查询主库

在数据库具有主从结构时,如果一个java方法注解成事务,在事务中for update能够对数据加锁;如果使用了for update的方法没有事务,那么查询完数据后,for update的锁就会被释放。唯一的用处是该条数据是从主库查出来的,能够避免主从延迟对查询数据准确性的影响。

3.for update的优点和弊端?

3.1.优点:

1)能够解决分布式服务中synchronized关键字不能保障线程安全的问题,同时避免使用分布式锁(可能有点麻烦)

3.2.弊端:

1)mysql中的for update,只适用于InnoDB引擎,必须结合事务才能在事务内对数据加锁

2)for update虽然是行级锁,但是在where条件没有命中索引的情况下会锁表

你可能感兴趣的:(数据库,分布式,java,数据库,mysql)