Mysql的锁问题:
1.1锁的概述:
Mysql锁的机制比较简单,不同的存储引擎支持不同的锁机制:MyISAM和MEMORY存储引擎支持表级锁;DBD支持页面锁,但是它也支持表级锁;InnoDB既支持行级锁也支持表级锁,但是默认情况下支持行级锁;
表级锁:开销小
1.2MyISAM表锁:
1.2.1 查询表锁争用情况:
mysql> SHOW STATUS LIKE 'table%';
±---------------------------±------+
| Variable_name | Value |
±---------------------------±------+
| Table_locks_immediate | 7 |
| Table_locks_waited | 0 |
| Table_open_cache_hits | 0 |
| Table_open_cache_misses | 0 |
| Table_open_cache_overflows | 0 |
±---------------------------±------+
Table_locks_waited 的值比较高,就说明存在着比较严重的表级锁竞争;
1.2.2 MYSQL表级锁的锁模式:
表共享读锁(Table Read Lock)
表独占写锁(Table Write Lock)
MySAM 表的读操作,不会塞其他用户对同一表的读请求,但会阻塞对同一表的写请求;对 MyISAM 表的写操作,则会阻塞其他用户对同一表的读和写操作;
MyISAM 表锁的读操作与写操作之间,以及写操作之间是串行的,当一个线程获得对一个表的写锁后,只有持有锁的线程可以对表进行更新操作。其他线程的读操作都会等待,直到锁被释放为止。
1.2.3 如何加表锁:
MyISAM 在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT 等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此,用户一般不需要直接用 LOCK TABLE 命令给 MyISAM 表显式加锁。
给 MyISAM 表显式加锁,一般是为了在一定程度模拟事务操作,实现对某一时间点多表的一致性读取。
什么是显示加锁:指的是把 Lock table table_name read 的加锁命令写出来;
代码示例:
1、当我用命令行链接数据库时候模拟session1用户,用Navicat链接作为session2用户;
session1进行写锁定,session2进行读操作可以看第一截图,session明显是阻塞在那了。
当session1立即释放锁后,session2立马拿到了读操作得结果;
锁之间的读写阻塞的关系大家可以在找个环境多试试一下,这里就不过多的演示了。
1.2.4 并发插入:(Councurrent Insert):
MyISAM 表的读和写是串行的,但这是就总体而言的。在一定条件下,MyISAM表也支持查询和插入操作的并发进行。MyISAM 存储引擎有一个系统变量 concurrent insert,专门用以控制其并发插人的行为其值分别可以为 0、1或 2。
当concurrent insert设置为0时,不允许并发插入
当concurrent insert设置为1时,如果MyISAM表中没有空洞(即表的中间没有被册除的行),MyISAM 允许在一个进程读表的同时,另一个进程从表尾插入记录。这也是MySOI的默认设置(or Auto)。
当concurrent insert设置为 2时,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录。
可以利用 MyISAM 存储引擎的并发插人特性来解决应用中对同一表查询和插人的锁争用,例如将 concurrent_insert 系统变量设为 2总是允许并发插人;同时,通过定期在系统空闲时执行 OPTIMIZE TABLE 语句来整理空间碎片,收回因删除记录而产生的中间空洞。
1.2.5 锁调度:
MyISAM 存储引擎的读锁和写锁是互斥的,读写操作是串行的。那么一个进程请求某个MyISAM 表的读锁,同时另一个进程也请求同一表的写锁,MySQL 如何处理呢?答案是写进程先获得锁。不仅如此,即使读请求先到锁等待队列,写请求后到,写锁也会插到读锁请求之前!这是因为 MySQL 认为写请求一般比读请求要重要。这也正是 MyISAM 表不太适合于有大量更新操作和查询操作应用的原因,因为,大量的更新操作会造成查询操作很难获得读锁,从而可能永远阻塞。不过我们可以通过一些设置来调节 MyISAM 的调度行为。
● 通过指定启动参数 low-priority-updates,使MyISAM引擎默认给予读请求以优先的权利。
● 通过执行命令SETLOW PRIORITY UPDATES=1,使该连接发出的更新请求优先级降低。
● 通过指定INSERT、UPDATE、DELETE 语句的 LOW_PRIORITY 属性,降低该语句的优先级。
虽然上面 3 种方法都是要么更新优先,要么查询优先的方法,但还是可以用其来解决查询相对重要的应用(如用户登录系统 )中读锁等待严重的问题。
另外,MvSOL 也提供了一种折中的办法来调节读写冲突,即给系统参数 max_write_lock_count设置一个合适的值,当一个表的读锁达到这个值后,MySQL 就暂时将写请求的优先级降低,给读进程一定获得锁的机会。
max_write_lock_count设置一个合适的值,当一个表的读锁达到这个值后,MySQL 就暂时将写请求的优先级降低,给读进程一定获得锁的机会。
这里还要强调一点:一些需要长时间运行的查询操作,也会使写进程“饿死”! 因此,应用中应尽量避免出现长时间运行的询操作,不要总想用一条 SELECT 语来解决问题,因为这种看似巧妙的 SQL 语句,往往较复杂,执行时间较长,在可能的情况下可以通过使用中间表等措施对 SQL 语句做一定的“分解”,使每一步查询都能在较短时间完成,从而减少锁冲突。如果复杂查询不可避免,应尽景安排在数据库空闲时段执行,比如一些定期统计可以安排在夜间执行。