行锁:只锁定表的一行记录,其他线程不能读
start TRANSACTION;
select * from fangwifi_agent where agentPin='fwf6a1790422f' for UPDATE;
start TRANSACTION;
select * from fangwifi_agent where agentPin='fwf6a1790422f' for UPDATE;
这行记录已经被锁住,第二个只能等待,等到第一个线程执行完了 COMMIT命令第二个线程才会取得结果。
页锁:锁定表的一行或多行记录,其他线程不能读
start TRANSACTION;
select * from fangwifi_agent where agentPin in ('fwf085d2b0113','fwf6a1790422f' ) for UPDATE;
表锁:锁定表的全部记录,其他线程不能读
select * from fangwifi_agent for UPDATE;
读锁和写锁的区别:在查询语句后加 lock in SHARE MODE 即为读锁,在查询语句后加 for UPDATE 即为写锁。
读锁和共享锁:一个人在某行记录加了读锁或共享锁,另一个人也可以在这行记录加读锁和共享锁,这把锁能共给所有读的人,若有人要获取写锁,执行写锁的线程只能等待,等到别人把这个记录读的共享锁释放掉,别人才可以获取写锁。
读锁:select * from fangwifi_agent where agentPin='fwf6a1790422f' lock in SHARE MODE;
共享锁:select * from fangwifi_agent where agentPin='fwf6a1790422f' lock in SHARE MODE;
写锁和排它锁:执行了写锁的线程会锁住这行记录,如果别的线程要再为它加写锁,或者加读锁,都只能等待,必须等到该线程的写锁释放掉才能执行。
写锁:select * from fangwifi_agent where agentPin='fwf6a1790422f' for UPDATE;
排它锁:select * from fangwifi_agent where agentPin='fwf6a1790422f' for UPDATE;
悲观锁:数据被外界修改保持保守态度(悲观),在整个数据处理过程中,将数据处于锁定状态,往往依靠数据库的锁机制实现,包括行锁,页锁,表锁,共享锁(读锁)和排它锁(写锁)。使用场景:写多读少,保证数据安全。
乐观锁:乐观锁假设认为数据一般情况下不会造成冲突,所以数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让用户返回错误信息,让用户决定如何去做或者程序自动重试。样例:数据库乐观锁,缓存乐观锁或者业务表加字段版本号实现。使用场景:读多写少,保证数据安全。
乐观锁只是在更新数据库那一刻锁表,其他时间不锁表,所以相对于悲观锁,效率更高
通过版本号实现
update user set amount=#{amount},version=version+1 where code=#{code} and version=#{version}
通过状态控制
update user set amount=#{amount} where code=#{code} and amount-#{amont}>=0