Mysql中那些锁机制之MyISAM

说到锁机制之前,先来看看Mysql的存储引擎,毕竟不同的引擎的锁机制也随着不同。

三类常见引擎:

MyIsam 不支持事务,不支持外键,所以访问速度快。锁机制是表锁,支持全文索引

InnoDB 支持事务、支持外键,所以对比MyISAM,InnoDB的处理效率差一些,并要占更多的磁盘空间保留数据和索引。锁机制是行锁,不支持全文索引

Memory数据是存放在内存中的,默认哈希索引,非常适合存储临时数据,服务器关闭后,数据会丢失掉。

如何选择存储引擎:

MyISAM:应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性要求不是很高。

InnoDB用于事务处理应用程序,支持外键,如果应用对事务的完整性有比较高的要求,在并发条件下要求数据的一致性。更新删除等频繁(InnoDB可以有效的降低由于删除和更新导致的锁定),对于数据准确性要求比较高的,此引擎适合。

Memory通常用于更新不太频繁的小表,用以快速得到访问结果。

Mysql中的锁

如果熟悉多线程,那么对锁肯定是有概念的,锁是计算机协调多个进程或线程对某一资源并发访问的机制。

Mysql中的锁分为表锁和行锁:

顾名思义,表锁就是锁住一张表,而行锁就是锁住一行。

表锁的特点:开销小,不会产生死锁,发生锁冲突的概率高,并且并发度低。

行锁的特点:开销大,会产生死锁,发生锁冲突的概率低,并发度高。

因此MyISAM和Memory引擎采用的是表锁,而InnoDB存储引擎采用的是行锁。

MyISAM的锁机制:

分为共享读锁和独占写锁。

读锁是:当某一进程对某张表进行读操作时(select),其他线程也可以读,但是不能写。简单的理解就是,我读的时候你不能写。

写锁是:当某一进程对某种表某张表的写时(insert,update,,delete),其他线程不能写也不能读。可以理解为,我写的时候,你不能读,也不能写。

因此MyISAM的读操作和写操作,以及写操作之间是串行的!MyISAM在执行读写操作的时候会自动给表加相应的锁(也就是说不用显示的使用lock table命令),MyISAM总是一次获得SQL语句所需要的全部锁,这也是MyISAM不会出现死锁的原因。

下面分别举关于写锁和读锁的例子:

写锁:

事务1 事务2

取得first_test表的写锁:

mysql> lock table first_test write;

Query OK, 0 rows affected (0.00 sec)


当前事务对查询、更新和插入操作都可以执行

mysql> select * from first_test ;

+----+------+

| id  | age   |

+----+------+

|  1   |   10  |

|  2   |   11  |

|  3   |   12  |

|  4   |   13  |

+----+------+

4 rows in set (0.00 sec)

mysql> insert into first_test(age) values(14);

Query OK, 1 row affected (0.11 sec)


其他事务对锁定表的查询被阻塞,需要等到锁被释放,才可以执行

mysql> select * from first_test;

等待......


mysql> unlock table;

Query OK, 0 rows affected (0.00 sec)

等待
 
mysql> select * from first_test;

+----+------+

| id  | age  |

+----+------+

|  1  |   10  |

|  2  |    11 |

|  3  |    12 |

|  4  |    13 |

|  5  |    14 |

+----+------+

5 rows in set (9 min 45.02 sec)

读锁例子如下:

事务1 事务2

获得表first_read的锁定

mysql> lock table first_test read;

Query OK, 0 rows affected (0.00 sec)

 

当前事务可以查询该表记录:

mysql> select * from first_test;

+----+------+

| id   |  age |

+----+------+

|  1   |    10 |

|  2   |    11 |

|  3   |    12 |

|  4   |    13 |

|  5   |    14 |

+----+------+

5 rows in set (0.00 sec)


其他事务也可以查到该表信息

mysql> select * from first_test;

+----+------+

| id   |  age  |

+----+------+

|  1   |    10 |

|  2   |    11 |

|  3   |    12 |

|  4   |    13 |

|  5   |    14 |

+----+------+

5 rows in set (0.00 sec)


但是当前事务不能查询没有锁定的表:

mysql> select * from goods;

ERROR 1100 (HY000): Table ‘goods‘

was not locked with LOCK TABLES

其他事务可以查询或更新未锁定的表:

mysql> select * from goods;

+----+------------+------+

| id   | name     | num |

+----+------------+------+

|  1  | firstGoods  |   11 |

|  3 | ThirdGoods |   11 |

|  4 | fourth            |   11 |

+----+------------+------+

10 rows in set (0.00 sec)


而且插入更新锁定的表都会报错:

mysql> insert into first_test(age) values(15);

ERROR 1099 (HY000): Table ‘first_test‘ was locked with

a READ lock and can‘t be updated

mysql> update first_test set age=100 where id =1;

ERROR 1099 (HY000): Table ‘first_test‘ was locked with

a READ lock and can‘t be updated


当更新被锁定的表时会等待:

mysql> update first_test set age=100 where id =1;

等待......


mysql> unlock table;

Query OK, 0 rows affected (0.00 sec)


mysql> update first_test set age=100 where id =1;

Query OK, 1 row affected (38.82 sec)

Rows matched: 1  Changed: 1  Warnings: 0

并发插入

刚说到Mysql在插入和修改的时候都是串行的,但是MyISAM也支持查询和插入的并发操作。

MyISAM中有一个系统变量concurrent_insert(默认为1),用以控制并发插入(用户在表尾插入数据)行为。

concurrent_insert为0时,不允许并发插入。

concurrent_insert为1时,如果表中没有空洞(中间没有被删除的行),MyISAM允许一个进程在读表的同时,另一个进程从表尾插入记录。

concurrent_insert为2时,无论MyISAM表中有没有空洞,都可以在末尾插入记录

事务1    事务2

mysql> lock table first_test read local;

Query OK, 0 rows affected (0.00 sec)

--加入local选项是说明,在表满足并发插入的前提下,允许在末尾插入数据

 

当前进程不能进行插入和更新操作

mysql> insert into first_test(age) values(15);

ERROR 1099 (HY000): Table ‘first_test‘ was locked

with a READ lock and can‘t be updated

mysql> update first_test set age=200 where id =1;

ERROR 1099 (HY000): Table ‘first_test‘ was locked

with a READ lock and can‘t be updated


其他进程可以进行插入,但是更新会等待:

mysql> insert into first_test(age) values(15);

Query OK, 1 row affected (0.00 sec)

mysql> update first_test set age=200 where id =2;

等待.....


当前进程不能不能访问其他进程插入的数据

mysql> select * from first_test;

+----+------+

| id | age  |

+----+------+

|  1 |  100 |

|  2 |   11 |

|  3 |   12 |

|  4 |   13 |

|  5 |   14 |

|  6 |   14 |

+----+------+

6 rows in set (0.00 sec)

 

释放锁以后皆大欢喜

mysql> unlock table;

Query OK, 0 rows affected (0.00 sec)

等待

插入的和更新的都出来的:

mysql> select * from first_test;

+----+------+

| id | age  |

+----+------+

|  1 |  100 |

|  2 |  200 |

|  3 |   12 |

|  4 |   13 |

|  5 |   14 |

|  6 |   14 |

|  7 |   15 |

+----+------+

7 rows in set (0.00 sec)


mysql> update first_test set age=200 where id =2;

Query OK, 1 row affected (1 min 39.75 sec)

Rows matched: 1  Changed: 1  Warnings: 0

需要注意的:

并发插入是解决对同一表中的查询和插入的锁争用。

如果对有空洞的表进行并发插入会产生碎片,所以在空闲时可以利用optimize table命令回收因删除记录产生的空洞。

锁调度

在MyISAM中当一个进程请求某张表的读锁,而另一个进程同时也请求写锁,Mysql会先让后者获得写锁。即使读请求比写请求先到达锁等待队列,写锁也会插入到读锁之前。

因为Mysql总是认为写请求一般比读请求重要,这也就是MyISAM不太适合有大量的读写操作的应用的原因,因为大量的写请求会让查询操作很难获取到读锁,有可能永远阻塞。

处理办法:

1、指定Insert、update、delete语句的low_priority属性,降低其优先级。

2、指定启动参数low-priority-updates,使得MyISAM默认给读请求优先的权利。

3、执行命令set low_priority_updates=1,使该连接发出的请求降低。

4、指定max_write_lock_count设置一个合适的值,当写锁达到这个值后,暂时降低写请求的优先级,让读请求获取锁。

但是上面的处理办法造成的原因就是当遇到复杂的查询语句时,写请求可能很难获取到锁,这是一个很纠结的问题,所以我们一般避免使用复杂的查询语句,如果如法避免,则可以再数据库空闲阶段(深夜)执行。

参考:

深入浅出Mysql数据库开发、优化与管理维护.第二版

版权声明:本文为博主原创文章,转载请注明出处。

时间: 2024-10-05 02:26:26

Mysql中那些锁机制之MyISAM的相关文章

Mysql中那些锁机制之InnoDB

我们知道mysql在曾经.存储引擎默认是MyISAM.可是随着对事务和并发的要求越来越高,便引入了InnoDB引擎.它具有支持事务安全等一系列特性. InnoDB锁模式 InnoDB实现了两种类型的行锁. 共享锁(S):同意一个事务去读一行,阻止其它事务获得同样的数据集的排他锁. 排他锁(X):同意获得排他锁的事务更新数据,可是组织其它事务获得同样数据集的共享锁和排他锁. 能够这么理解: 共享锁就是我读的时候,你能够读,可是不能写.排他锁就是我写的时候.你不能读也不能写.事实上就是MyISAM的

Mysql中的锁机制

原文:http://blog.csdn.net/soonfly/article/details/70238902 锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的 计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所有数据库必须解决的一 个问题,锁冲突也是影响数据库并发访问性能的一个重要因素.从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂.本章我们着重讨论MySQL锁机制 的特点,常见的锁问题

【mysql】mysql中的锁机制

一.分类 MySQL的锁机制不同的存储引擎支持不同的锁机制,分为表级锁.行级锁.页面锁.MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking):BDB存储引擎采用的是页面锁(page-level locking),但也支持表级锁:InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁 表级锁:开销小,加锁快:不会出现死锁:锁定粒度大,发生锁冲突的概率最高,并发度最低. 行级锁:开销大,加锁慢:会出现死锁:

mysql中的锁机制之概念篇

锁的概念 ①.锁,在现实生活中是为我们想要隐藏于外界所使用的一种工具. ②.在计算机中,是协调多个进程或线程并发访问某一资源的一种机制. ③.在数据库当中,除了传统的计算资源(CPU.RAM.I/O等等)的争用之外,数据也是一种供许多用户共享访问的资源. ④.如何保证数据并发访问的一致性.有效性,是所有数据库必须解决的一个问题. ⑤.锁的冲突也是影响数据库并发访问性能的一个重要因素. MySQL锁的概述 相对于其它数据库而言,MySQL的锁机制比较简单,其最 显著的特点是不同的存储引擎支持不同的

mysql中的锁机制之悲观锁和乐观锁

1.悲观锁? 悲观锁顾名思义就是很悲观,悲观锁认为数据随时就有可能会被外界进行修改,所以悲观锁一上来就会把数据给加上锁.悲观锁一般都是依靠关系型数据库提供的锁机制,然而事实上关系型数据库中的行锁,表锁不论是读写锁都是悲观锁. 2.乐观锁? 乐观锁顾名思义,就是很乐观,每次自己操作数据的时候认为没有人会来修改它,所以不会去对数据进行加锁.但是在更新的时候会去判断在此期间数据有没有被修改,需要用户自己去实现乐观锁.乐观锁不会发生并发抢占资源,只有在提交操作的时候检查是否违反数据完整性. 2.1.为什

MySQL中的锁

数据库中有很多锁,但锁是为了解决什么问题?具体都有哪些锁呢?这篇文章简单对MySQL中的锁做了一个总结 一.锁的设计是为了解决什么问题? 当多用户读写数据的时候,就有可能会出现同一时刻对同一条数据的读写,如果是大家都只是对同一条数据进行读,无所谓,大家读到数据都是一样的,但当有的想要读取数据,有的想要修改数据的时候,或者大家都想要修改数据的时候就会出现问题.比如有一行数据现在值是5,同一时刻有两个用户都想要修改这行数据,用户1和用户2此刻读到的数据都是5,用户1在数据5的基础上加了1变成6,并将

MySQL数据库InnoDB存储引擎中的锁机制

MySQL数据库InnoDB存储引擎中的锁机制    http://www.uml.org.cn/sjjm/201205302.asp   00 – 基本概念 当并发事务同时访问一个资源的时候,有可能导致数据不一致.因此需要一种致机制来将访问顺序化. 锁就是其中的一种机制.我们用商场的试衣间来做一个比喻.试衣间供许多消费者使用.因此可能有多个消费者同时要试衣服.为了避免冲突,试衣间的门上装了锁.试衣服的人在里边锁住,其他人就不能从外边打开了.只有里边的人开门出来,外边的人才能进去. - 锁的基本

MySQL数据库锁机制之MyISAM引擎表锁和InnoDB行锁详解

MySQL中的锁概念 Mysql中不同的存储引擎支持不同的锁机制.比如MyISAM和MEMORY存储引擎采用的表级锁,BDB采用的是页面锁,也支持表级锁,InnoDB存储引擎既支持行级锁,也支持表级锁,默认情况下采用行级锁. Mysql3中锁特性如下: 表级锁:开销小,加锁块:不会出现死锁,锁定粒度大,发生锁冲突的概率最高,并发度最低. 行级锁:开销大,加锁慢:会出现死锁:锁定粒度最小,发生锁冲突的概率最低,并发性也最高. 页面锁:开销和加锁界于表锁和行锁之间,会出现死锁:锁定粒度界与表锁和行锁

转载 深入浅出mysql事务处理和锁机制

1. 事务处理和并发性 1.1. 基础知识和相关概念 1 )全部的表类型都可以使用锁,但是只有 InnoDB 和 BDB 才有内置的事务功能. 2 )使用 begin 开始事务,使用 commit 结束事务,中间可以使用 rollback 回滚事务. 3 )在默认情况下, InnoDB 表支持一致读. SQL 标准中定义了 4 个隔离级别: read uncommited , read commited , repeatable read , serializable . read uncomm