• mysql的事务和数据库锁的关系


    数据库加事务并不是数据就安全来了,事务和锁要分析清楚和配合使用

    问题背景处于对高并发的秒杀环节的理解整理如下:


    秒杀的时候高并发主要注意
    1、在秒杀的情况下,肯定不能如此高频率的去读写数据库,会严重造成性能问题的
    必须使用缓存,将需要秒杀的商品放入缓存中,并使用锁来处理其并发情况。当接到用户秒杀提交订单的情况下,先将商品数量递减(加锁/解锁)后再进行其他方面的处理,处理失败在将数据递增1(加锁/解锁),否则表示交易成功。
    当商品数量递减到0时,表示商品秒杀完毕,拒绝其他用户的请求。
    2、这个肯定不能直接操作数据库的,会挂的。直接读库写库对数据库压力太大,要用缓存。
    把你要卖出的商品比如10个商品放到缓存中;然后在memcache里设置一个计数器来记录请求数,这个请求书你可以以你要秒杀卖出的商品数为基数,比如你想卖出10个商品,只允许100个请求进来。那当计数器达到100的时候,后面进来的就显示秒杀结束,这样可以减轻你的服务器的压力。然后根据这100个请求,先付款的先得后付款的提示商品以秒杀完。
    3、首先,多用户并发修改同一条记录时,肯定是后提交的用户将覆盖掉前者提交的结果了。
    这个直接可以使用加锁机制去解决,乐观锁或者悲观锁。
    乐观锁,就是在数据库设计一个版本号的字段,每次修改都使其+1,这样在提交时比对提交前的版本号就知道是不是并发提交了,但是有个缺点就是只能是应用中控制,如果有跨应用修改同一条数据乐观锁就没办法了,这个时候可以考虑悲观锁。
    悲观锁,就是直接在数据库层面将数据锁死,类似于oralce中使用select xxxxx from xxxx where xx=xx for update,这样其他线程将无法提交数据。
    除了加锁的方式也可以使用接收锁定的方式,思路是在数据库中设计一个状态标识位,用户在对数据进行修改前,将状态标识位标识为正在编辑的状态,这样其他用户要编辑此条记录时系统将发现有其他用户正在编辑,则拒绝其编辑的请求,类似于你在操作系统中某文件正在执行,然后你要修改该文件时,系统会提醒你该文件不可编辑或删除。
    4、不建议在数据库层面加锁,建议通过服务端的内存锁(锁主键)。当某个用户要修改某个id的数据时,把要修改的id存入memcache,若其他用户触发修改此id的数据时,读到memcache有这个id的值时,就阻止那个用户修改。
    5、实际应用中,并不是让mysql去直面大并发读写,会借助“外力”,比如缓存、利用主从库实现读写分离、分表、使用队列写入等方法来降低并发读写。

    mysql
    -----MyISAM引擎:
    使用的是表级锁。理解为锁住整个表,可以同时读,写不行。

    ----innoDB
    使用的是行级锁,它也支持表级锁。单独的一行记录加锁 。
    事务和数据库锁的关系如下

    读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。
    快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。
    当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。

    锁类型
    共享锁(S锁):假设事务T1对数据A加上共享锁,那么事务T2可以读数据A,不能修改数据A。
    排他锁(X锁):假设事务T1对数据A加上共享锁,那么事务T2不能读数据A,不能修改数据A。
    我们通过update、delete等语句加上的锁都是行级别的锁。只有LOCK TABLE … READ和LOCK TABLE … WRITE才能申请表级别的锁。


    当执行select 的时候 默认是不加锁的 (快照读) (这种说法在隔离级别为Serializable中不成立)
    如果想要对某个行数据加锁需要 执行如下:
    select * from table where num = 200 lock in share mode 共享锁
    select * from table where num = 200 for update 行级锁
    这是通过显示加锁实现的

    当执行update,insert,delete的时候 默认是加行锁的

    Cluster Index:聚簇索引
    InnoDB存储引擎的数据组织方式,是聚簇索引表:完整的记录,存储在主键索引中,通过主键索引,就可以直接获取记录所有的列。


    Read Uncommited(RU):读未提交,一个事务可以读到另一个事务未提交的数据!
    Read Committed (RC):读已提交,一个事务可以读到另一个事务已提交的数据!
    Repeatable Read (RR):可重复读,加入间隙锁,一定程度上避免了幻读的产生!注意了,只是一定程度上,并没有完全避免!我会在下一篇文章说明!另外就是记住从该级别才开始加入间隙锁(这句话记下来,后面有用到)!
    Serializable:串行化,该级别下读写串行化,且所有的select语句后都自动加上lock in share mode,即使用了共享锁。因此在该隔离级别下,使用的是当前读,而不是快照读。
    完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞
    完全串行化的读,每次写都需要获得所有行级锁,读写相互都会阻塞

    RC/RU+条件列非索引
    select * from table where num = 200 lock in share mode 共享锁
    select * from table where num = 200 for update 行锁

    RR/Serializable+条件列非索引
    select * from table where num = 200
    在RR级别下,不加任何锁,是快照读。(可重读的时候也不加锁)
    在Serializable级别下 ,完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞

    select * from table where num = 200 lock in share mode
    在Serializable级别下, 全表所有记录都加共享锁

    select * from table where num = 200 for update
    在Serializable级别下, 全表所有记录都加上行锁

    所以:Serializable 都是表锁


    参见:https://www.cnblogs.com/rjzheng/p/9950951.html,https://blog.csdn.net/xf552527/article/details/78811262

    以上是对事务和锁的理解

    参见:https://fengberlin.github.io/post/seckill/  高并发处理思路,https://blog.csdn.net/GallenZhang/article/details/78626730 

  • 相关阅读:
    NKOI 1363 (基础二分)
    POJ 1321 棋盘问题(dfs八皇后变形)
    UVA 1368 DNA(模拟+贪心)
    暴力(解数阵)
    A Linear Algebra Problem(唯一性的判定)
    hdu 1565 方格取数(1)
    hdu 1074 Doing Homework
    hdu 1233 还是畅通工程
    hdu 1232 畅通工程
    hdu 1213 How Many Tables
  • 原文地址:https://www.cnblogs.com/ljy-skill/p/10622865.html
Copyright © 2020-2023  润新知