MySQL 锁的基本原理
多个事务同时并发更新一行数据的时候,会有脏写的问题。
脏写是靠锁机制实现,多个事务更新一行数据的时候串行化,避免同时更新一行数据。
更新一行数据必须把数据页从磁盘文件里读取到缓存页里,然后才能更新数据。
所以说,缓存页数据和关联的锁数据结构,都是在内存里的。
事务A更新完了数据,释放锁。然后看是否有别的事务也对这行数据加锁了。
发现事务B也加锁了,会将等待状态修改为false,唤醒事务B执行。
Java里的锁,也同样具备这些锁的概念。
锁引申出很多其他的概念,比如读写锁,共享/独占锁,公平/非公平锁等等。
共享锁&独占锁
MySQL支持 S(Share) 锁、X(Exclude) 锁。多个事务要修改同一个数据,加的是X锁。
共享锁和独占锁是互斥的;共享锁和共享锁不互斥。
先加共享锁,不能再加独占锁;先加独占锁,不能再加共享锁。
当一个事务更新一行数据时,其他的事务读取这行数据时,默认开启 MVCC 机制,不需要加锁。
但可以使用特殊的语法加锁:
查询数据时可以加 S 锁:select * from table lock in share mode //lock in share mode:查询的时候对一行数据加共享锁。
查询操作还能加互斥锁:select * from table for update //查出来数据以后还要更新
总结:
更新数据必然加独占锁,此时别的事务不能更新;
查询操作默认不加锁,一般是基于mvcc机制读快照版本。
一般不会在数据库层面做复杂的手动加锁操作,基于redis/zookeeper的分布式锁来实现业务系统的锁逻辑。
加锁逻辑隐藏在SQL语句里,在你的业务系统层面其实是非常的不好维护的
表级锁和metadata lock
执行DDL的时候,会阻塞所有增删改操作;执行增删改的时候,会阻塞DDL操作。
执行DDL语句如 alter table 之类的语句,加锁是通过MySQL通用的 Metadata Locks 实现的。
但是表锁是InnoDB存储引擎的概念,InnoDB存储引擎提供了自己的表级锁,跟DDL语句用的元数据锁不是一个概念。
