首页 > 编程知识 正文

mysql锁表命令,数据库锁有哪些

时间:2023-05-06 18:04:31 阅读:31730 作者:1608

数据库管理系统(DBMS )并发控制的任务是确保当多个事务同时访问数据库中的同一数据时,不破坏事务的独立性和统一性以及数据库的统一性。 以下是并发操作导致的数据不一致问题的示例。

在现有的两处列车售票窗口中,同时读取某列车车票数据库的车票余额为x。 在两个售票窗口同时卖出一张票,同时将余额修改为X -1并写回数据库,实际卖出了两张火车票,但数据库里记录的只有一张。 这是因为两个事务读取并同时修改相同的数据,一个事务的提交结果破坏了另一个事务的提交结果,该数据的修改丢失,事务的独立性受损。 同时控制需要解决的是这样的问题。

分块、时间戳、乐观并发控制(乐观锁定)和悲观并发控制(悲观锁定)是并发控制中主要采用的技术手段。

锁上

由于事务同时访问一个资源可能会导致数据不一致,因此需要一种对数据访问进行顺序化的机制来确保数据库的数据完整性。 摇滚是其中的机制之一。

在计算机科学中,锁定是一种同步机制,用于在执行多线程时强制限制对资源的访问,这意味着并发控制用于满足互斥的要求。

锁定分类(oracle )

另一方面,根据操作可以分为DML锁定、DDL锁定

二、根据锁定粒度可分为表级锁定、行级锁定、页面级锁定(mysql )

三、根据锁定等级可以分为共享锁定、排他锁定

四.按锁定方式划分,可分为自动锁定、显示锁定

五.根据使用方法不同,可以分为乐观锁定和悲观锁定

DML锁定(数据锁定)用于保护数据的完整性,如行级锁定(行锁定) tx锁定)和表级锁定(TM锁定)。 DDL锁定(dictionary locks )用于保护数据库对象(如表和索引)的结构定义。 其中包括独占DDL锁(Exclusive DDL lock )、共享DDL锁(Share DDL lock )和可中断解析锁(Breakable parse locks ) )

MySQL中的行级锁定、表级锁定和页级锁定

在计算机科学中,锁定是一种同步机制,用于在执行多线程时强制限制对资源的访问,这意味着并发控制用于满足互斥的要求。

行级锁定

行锁是Mysql中锁粒度最细的锁,表示只锁定当前操作的行。 低级别锁定大大减少了数据库操作冲突。 锁定粒度最小,但锁定开销也最大。 行级锁定包括共享锁定和独占锁定。

特长

费用大,上锁慢; 发生死锁; 锁粒度最小,发生锁碰撞的概率最低,同时性也最高。

时钟级锁定

表锁是MySQL中锁粒度最大的锁,表示锁定当前操作的整个表。 这种方法实现简单、资源消耗少,大多数MySQL引擎都支持。 最常用的MYISAM和INNODB支持表级锁定。 表级锁定分为表共享读锁定(共享锁定)和表独占写锁定。

特长

支出小,上锁快; 不发生死锁; 锁粒度大,出现锁碰撞的概率最高,同时性最低。

页面级锁定

页面锁是MySQL锁粒度介于行级锁和表级锁之间的锁。 时钟级锁定速度快,但碰撞多,行级碰撞少,但速度慢。 所以采取折中的页面级别,一次锁定一组相邻的记录。 BDB支持页面级锁定

特长

开销和锁定时间在表锁和行锁之间; 发生死锁; 锁的粒度在工作台锁和行锁之间,并发性一般

MySQL常见存储引擎的锁定机制

MyISAM和MEMORY采用了表锁(table-level locking )

BDB采用“页面锁定”或表级锁定,默认值为页面锁定

InnoDB支持行级锁定和表级锁定,缺省情况下为行级锁定

Innodb行锁和表锁

如上所述,Innodb引擎同时支持行锁和表锁,但什么时候锁定整个表? 另外,什么时候只锁定一行?

InnoDB行锁定是通过锁定索引上的索引项实现的。 这是通过MySQL与Oracle不同,它锁定数据块中相应的数据行来实现的。 行锁实现(如InnoDB )的特点是InnoDB仅在索引条件下获取数据时使用行级锁,否则InnoDB使用表锁

在实际的APP应用中,请特别注意InnoDB行锁的这一特性。 否则,可能会引起大量的锁定竞争,影响并发性。

所有行级锁定都是基于索引的,如果索引在SQL语句中不可用,则不使用行级锁定。 行锁的缺点是需要大量的锁定资源,因此速度慢,内存消耗大。

行级锁定和死锁

MyISAM不会发生死锁。 由于MyISAM始终一次获取所需的所有锁定,因此它要么满足一切,要么等待一切。 在InnoDB中,锁定是分阶段获得的,有可能是死锁。

在MySQL中,行级锁定不会直接锁定记录,而是锁定索引。 索引有两种类型:主键索引和非主键索引。如果一个sql语句操作了主键索引,MySQL将锁定此主键索引。 如果语句操作了非主键索引,MySQL将锁定非主键索引,然后锁定相关主键索引。 对于UPDATE、DELETE操作,MySQL不仅锁定在WHERE条件下扫描的所有索引记录,还锁定相邻的键值,即所谓的next-ke

y locking。

当两个事务同时执行,一个锁住了主键索引,在等待其他相关索引。另一个锁定了非主键索引,在等待主键索引。这样就会发生死锁。

发生死锁后,InnoDB一般都可以检测到,并使一个事务释放锁回退,另一个获取锁完成事务。

有多种方法可以避免死锁,这里只介绍常见的三种

1、如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。

2、在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;

3、对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;

MySQL中的共享锁与排他锁

共享锁(Share Lock)

共享锁又称读锁,是读取操作创建的锁。其他用户可以并发读取数据,但任何事务都不能对数据进行修改(获取数据上的排他锁),直到已释放所有共享锁。

如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁。获准共享锁的事务只能读数据,不能修改数据。

用法

SELECT ... LOCK IN SHARE MODE;

在查询语句后面增加LOCK IN SHARE MODE,Mysql会对查询结果中的每行都加共享锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请共享锁,否则会被阻塞。其他线程也可以读取使用了共享锁的表,而且这些线程读取的是同一个版本的数据。

排他锁(eXclusive Lock)

排他锁又称写锁,如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。

用法

SELECT ... FOR UPDATE;

在查询语句后面增加FOR UPDATE,Mysql会对查询结果中的每行都加排他锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请排他锁,否则会被阻塞。

意向锁

InnoDB还有两个表锁:

意向共享锁(IS):表示事务准备给数据行加入共享锁,也就是说一个数据行加共享锁前必须先取得该表的IS锁

意向排他锁(IX):类似上面,表示事务准备给数据行加入排他锁,说明事务在一个数据行加排他锁前必须先取得该表的IX锁。

意向锁是InnoDB自动加的,不需要用户干预。

对于insert、update、delete,InnoDB会自动给涉及的数据加排他锁(X);对于一般的Select语句,InnoDB不会加任何锁,事务可以通过以下语句给显示加共享锁或排他锁。

共享锁:SELECT ... LOCK IN SHARE MODE;

排他锁:SELECT ... FOR UPDATE;

乐观锁和悲观锁

乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。

无论是悲观锁还是乐观锁,都是人们定义出来的概念,可以认为是一种思想。其实不仅仅是关系型数据库系统中有乐观锁和悲观锁的概念,像memcache、hibernate、tair等都有类似的概念。

针对于不同的业务场景,应该选用不同的并发控制方式。所以,不要把乐观并发控制和悲观并发控制狭义的理解为DBMS中的概念,更不要把他们和数据中提供的锁机制(行锁、表锁、排他锁、共享锁)混为一谈。其实,在DBMS中,悲观锁正是利用数据库本身提供的锁机制来实现的。

下面来分别学习一下悲观锁和乐观锁。

悲观锁

在关系数据库管理系统里,悲观并发控制(又名“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)是一种并发控制的方法。它可以阻止一个事务以影响其他用户的方式来修改数据。如果一个事务执行的操作都某行数据应用了锁,那只有当这个事务把锁释放,其他事务才能够执行与该锁冲突的操作。

悲观并发控制主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中。

悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度(悲观),因此,在整个数据处理过程中,将数据处于锁定状态。 悲观锁的实现,往往依靠数据库提供的锁机制 (也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)

在数据库中,悲观锁的流程如下:

在对任意记录进行修改前,先尝试为该记录加上排他锁(exclusive locking)。

如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常。 具体响应方式由开发者根据实际需要决定。

如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。

其间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁或直接抛出异常。

MySQL InnoDB中使用悲观锁

要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,无私的过客执行一个更新操作后,MySQL会立刻将结果进行提交。set autocommit=0;

//0.开始事务begin;/begin work;/start transaction;(三者选一就可以)//1.查询出商品信息selectstatus fromt_goods whereid=1forupdate;//2.根据商品信息生成订单insert intot_orders (id,goods_id)values (null,1);//3.修改商品status为2update t_goods setstatus=2;//4.提交事务commit;/commit work;

上面的查询语句中,我们使用了select…for update的方式,这样就通过开启排他锁的方式实现了悲观锁。此时在t_goods表中,id为1的 那条数据就被我们锁定了,其它的事务必须等本次事务提交之后才能执行。这样我们可以保证当前的数据不会被其它事务修改。

上面我们提到,使用select…for update会把数据给锁住,不过我们需要注意一些锁的级别,MySQL InnoDB默认行级锁。行级锁都是基于索引的,如果一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁把整张表锁住,这点需要注意。

优点与不足

悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;另外,在只读型事务处理中由于不会产生冲突,也没必要使用锁,这样做只能增加系统负载;还有会降低了并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数

乐观锁

在关系数据库管理系统里,乐观并发控制(又名“乐观锁”,Optimistic Concurrency Control,缩写“OCC”)是一种并发控制的方法。它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,正在提交的事务会进行回滚。乐观事务控制最早是由lydy(H.T.Kung)教授提出。

乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。

相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。

数据版本,为数据增加的一个版本标识。当读取数据时,将版本标识的值一同读出,数据每更新一次,同时对版本标识进行更新。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的版本标识进行比对,如果数据库表当前版本号与第一次取出来的版本标识值相等,则予以更新,否则认为是过期数据。

实现数据版本有两种方式,第一种是使用版本号,第二种是使用时间戳。

使用版本号实现乐观锁

使用版本号时,可以在数据初始化时指定一个版本号,每次对数据的更新操作都对版本号执行+1操作。并判断当前版本号是不是该数据的最新的版本号。

1.查询出商品信息select(status,status,version)fromt_goods whereid=#{id}2.根据商品信息生成订单3.修改商品status为2update t_goods

setstatus=2,version=version+1whereid=#{id}andversion=#{version};

优点与不足

乐观并发控制相信事务之间的数据竞争(data race)的概率是比较小的,因此尽可能直接做下去,直到提交的时候才去锁定,所以不会产生任何锁和死锁。但如果直接简单这么做,还是有可能会遇到不可预期的结果,例如两个事务都读取了数据库的某一行,经过修改以后写回数据库,这时就遇到了问题

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。