mysql锁表解决高并发_使用mysql中的锁解决高并发问题

多核计算机的出现,计算机实现真正并行计算,可以在同一时刻,执行多个任务。在多线程编程中,因为线程执行顺序不可控导致的数据错误。比如,多线程的理想状态是这样的

84c2ae41bed0cce209d15da7820a16ec.png

多线程理想.jpg

但是实际情况是这样的:

d921f5d8ae0301cde1161a2c76328c14.png

多线程实际.jpg

在网络编程中,在同一时刻,多个客户端同时请求同一个资源,如果不做控制,也会带来数据错误。比如在同一时间有10000人去抢10张火车票,10张火车票有可能会买给100个人,这显然是不符合要求的。

在多线程编程中,为了解决线程执行不可控带来的问题,通常情况下都是通过加锁来实现数据同步的。在网络编程中,也可以通过加锁机制来控制。

在网络编程中,可以通过给数据库加锁,达到控制并发的目的。在php开发时,基本都是使用mysql作为数据库。所以,就会给mysql加锁控制网络并发引起数据错误问题。

MySQL的存储引擎不是要说MySQL的锁吗,怎么说上存储引擎了?因为MySQL存储引擎不同,锁也会不同。MySQL有MyISAM 和InnoDB两种存储引擎,现在主要使用InnoDB,所以主要介绍InnoDB下锁的使用。

InnoDB引擎支持事务操作,使用事务可以保证多条sql语句执行的完整性(要不都成功,要不都失败)事务是由一组SQL语句组成的逻辑处理单元,事务具有4属性原子性(Actomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。

一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以操持完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。

隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。

持久性(Durable):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。多个事务并发执行会带来新的问题更新丢失(Lost Update):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个 事务都不知道其他事务的存在,就会发生丢失更新问题——最后的更新覆盖了其他事务所做的更新。例如,两个编辑人员制作了同一文档的电子副本。每个编辑人员独立地更改其副本,然后保存更改后的副本,这样就覆盖了原始文档。最后保存其更改保存其更改副本的编辑人员覆盖另一个编辑人员所做的修改。如果在一个编辑人员完成并提交事务之前,另一个编辑人员不能访问同一文件,则可避免此问题

脏读(Dirty Reads):一个事务正在对一条记录做修改,在这个事务并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”的数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做“脏读”。

不可重复读(Non-Repeatable Reads):一个事务在读取某些数据已经发生了改变、或某些记录已经被删除了!这种现象叫做“不可重复读”。

幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。

曾经年少无知的我,以为使用事务就能保证并发情况下数据同步问题,后来的一次惨痛经历才明白了,事务不能保证并发情况的数据同步问题,需要事务和锁同时使用才能保证。

锁的种类乐观锁 机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。相对悲观锁而言,乐观锁更倾向于开发运用。

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

MySQL中锁的种类乐观锁和悲观锁是一种思想,不是具体实现,在MySQL中,有锁的具体的实现方式

(文中的线程在MySQL中可以视作MySQL的连接)共享锁 一个线程在持有锁时,其他的线程可以查询被锁的数据,但是不能修改,不能删除。实现方式

SELECT * FROM table_name WHERE id =? lock in share mode;

排它锁 一个线程在持有锁时,其他的线程不能查询,不能更新,不能删除被锁的数据,直到锁被释放.

SELECT * FROM table_name WHERE id =? for update

总结一下:共享锁类似于java中的读锁,一个线程在持有乐观锁的时候,其他的线程也可以对被锁的数据进行读操作,但是不能对被锁的数据进行删除和更新操作;排他锁类似于java的写锁,一个线程持有写锁的时候,其他的线程不能再对被锁的数据进行任何查询,更新,删除操作。

重点 InnoDB的行锁是基于索引实现的,如果在查询中不使用索引,会锁表。

MySQL锁粒度表级锁 是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MyISAM与InnoDB都支持表级锁定。表级锁分为表共享读锁与表独占写锁。

行级锁 是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁 和 排他锁。

总结InnoDB的锁配合事务使用

MySQL有共享锁和排它锁

使用共享锁时,其他线程(连接)可以查询数据,但是不能更新和删除数据,使用排它锁时,不能查询数据不能更新数据,不能删除数据

MySQL的InnoDB引擎支持行级锁和表级锁,行级锁

InnoDB的行级锁是基于索引的,加锁是对索引加锁,加锁时没有索引时会锁住整张表(测试时发现没加索引也是行锁)

其他:

事务命令

表的引擎类型必须是innodb类型才可以使用事务,这是mysql表的默认引擎

查看表的创建语句,可以看到engine=innodb-- 选择数据库

use jing_dong;

-- 查看goods表

show create table goods;

开启事务,命令如下:开启事务后执行修改命令,变更会维护到本地缓存中,而不维护到物理表中begin;或者start transaction;

提交事务,命令如下将缓存中的数据变更维护到物理表中commit;

回滚事务,命令如下:放弃缓存中变更的数据rollback;

注意修改数据的命令会自动的触发事务,包括insert、update、delete

而在SQL语句中有手动开启事务的原因是:可以进行多次数据的修改,如果成功一起成功,否则一起会滚到之前的数据

行锁查询错误:

cc5d547841745dd83b63f2dadf47f9ec.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值