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条件没有命中索引的情况下会锁表