zoukankan      html  css  js  c++  java
  • mysql

    MyISAM存储引擎:开销小,加锁快,无死锁。锁定粒度大,并发度低,容易发生锁冲突。   不支持事务。            采用表锁 (操作时对操作的表上锁) 基本不用了

    innoDB存储引擎:开销大,有死锁,锁定粒度小,不容易发生冲突。                                                                       采用行锁(每句sql执行时对操作行上锁),但是也支持表锁     mysql默认引擎

    问题:库存超卖

    库存1,结果两个人同时购买,第一个人判断后还有1个剩余,于是执行 update 操作, 这时第二个人开始判断,此时update还没结束,剩余还是1,于是也开始进update操作,导致库存变为-1.

    1. 悲观锁,在判断的select语句中加入行锁,与update语句互斥,保证第1个人提交事务前,第2个人不能操作这个货物。

    2.乐观锁,添加版本字段,查询时更新版本字段,版本字段变化时,不能更新。

    select num, version from warehouse where id = 商品编号;   查询数量同时查出版本,比如111

    update warehouse set num = num - 1, version = version + 1 where version = 111; 这样假如warhouse在查询后这个商品被更改过,这条将不会更改任何字段。如果成功了版本同时改变为112。

    reference: http://www.zsythink.net/archives/1233/

    事务隔离:

    读未提交: read-uncommitted     可能问题:脏读,幻读,不可重复读           A修改操作后没有提交,B也能看到改动

    读已提交:read-commited           可能问题:幻读,不可重复读                      A修改操作后提交了,B才可以看到改动,保证了看到的数据是真实存在的,对面没提交的不会看见,防止了脏读

    可重复读: repeatable-read        可能问题:不可重复读                                 A修改操作后,B的操作也用到了相同的表后才可以看到A的改动,保证一个事务中查询条数据的结果保持保持一致,防止了幻读,但是对于对面新加的数据还是会看到导致不一致。

    可序列化:serialiazable               三种都不会出现                                           A修改操作时,B连读取都做不到。    这样最安全,但是无法并发,效率太低

    脏读:             读到了别人未提交的改动  (表的数据实际没有变化,但是你以为变了)        B修改了数据还没提交,A查到了,B的数据提交失败回滚了,A以为B改完了。

    幻读:             数量不对                           ( 表的数据数量变化)                                           A在查询后, B添加或者删除了数据, A以为数据没变。

    不可重复读:  读取和修改时状态不一致  (数据值发生变化)                                               A在查询后,B修改了数据值,A还是以旧数据作为判断条件。

     不可重复读  和 幻读差不多,不过一个是莫名其妙多了一行,一个是莫名其妙值变了。 所以库存超卖是不可重复读。

    1.

    查询数据库事务隔离等级:

    SHOW VARIABLES LIKE '%isolation';  #网上查的版本是tx_isolation, 我的版本是 transaction_isolation,所以直接用模糊查询

    一般都是 可重复读级别

    2.修改隔离等级:

    SET transaction_isolation = 'read-uncommitted';

    mysql的锁:   表名 index_test

    1. 查看表存储引擎

    SHOW TABLE STATUS LIKE 'index_test';

     2. 修改表存储引擎

    ALTER TABLE index_test ENGINE = MYISAM;   #修改表引擎
    SHOW TABLE STATUS LIKE 'index_test';

    3. 表锁

    表锁有读锁,和写锁

    读锁:不让其他连接修改表, 是可以查询的!

    写锁:不让其他连接查询和修改表。

    - -|||注意别只凭字面意思理解,有时候容易造成读锁是不让读,写锁是不让写的错觉(比如我。。。)

    1).对index_test 添加表写锁   (这时在当前数据库连接会话下是可以修改表的。)

    LOCK TABLE index_test WRITE;

    2). 新建一个数据库连接(文件 -> 新链接     不是新打开一个查询编辑器或者窗口= =sqlyog打开新窗口还是用的同一个链接。。。)

    然后修改index_test表  (查询也是一样的结果)

    可以看到 会一直显示处理中。

    3).这时在第一个连接中解锁表

    UNLOCK TABLES;

    发现第二个连接的修改语句立刻执行完毕。

    个人测试(我有一个大胆的想法):

    建立连接a,b,c

    a锁表

    b修改 - 进入等待

    c输入解锁

    b依旧等待

    c锁表 - 进入等待

    a解锁 - b执行完毕,c执行完毕

    a锁表 - 进入等待。。。因为c把表锁了

    c解锁

    可以得出结论:不同的连接的锁表和解锁是独立的。。。

    4).对index_test 添加表读锁   (这时在当前数据库连接会话下是可以修改表的。)

    LOCK TABLE index_test READ;

    这时第二个连接,修改时会进入等待状态,但是可以查询。

    4. 行锁

    myisam 只有表级锁,所以要切换回innodb

    行锁:执行语句时,只锁住相关数据行,而不是整个表。 这也是innodb能支持事务的主要原因之一。(要是锁表,那么一次事务中用到多个表的时候,会导致数据库很多表被锁,大幅拖慢效率)

    innodb会自动给修改语句添加行锁。

    1. 修改表引擎 

    ALTER TABLE index_test ENGINE = INNODB;

    2.取消自动提交(innodb会把单独的sql语句作为事务直接提交,取消后必须commit才能提交一次事务)

    SET autocommit = 0;

    3. 进行一次修改

    UPDATE index_test SET key1 = 1 WHERE t_id = 1; 

    新建连接2,对表进行修改

    UPDATE index_test SET key1 = 3 WHERE t_id = 1; 

    连接2 进入等待

    过一段时间后提示超时

    连接1 提交修改

    COMMIT;

    连接2 再次尝试修改,成功

    个人测试:既然是行锁,那么尝试在连接2修改不同行的数据看看结果-。-

    连接1:

    UPDATE index_test SET key1 = 1 WHERE t_id = 1; 

    连接2:

    UPDATE index_test SET key1 = 3 WHERE t_id = 2; 

    连接2直接修改成功。 

    5.为查询语句添加行锁

    悲观锁解决库存超卖问题:

    悲观锁,在判断的select语句中加入行锁,保证第1个人提交事务前,第2个人不能操作这个货物。

    用index_test 表作为例子

     t_id = 1这一行中, key = 1。假设为key1 是一种货物,剩余1个

    a 进行查询,同时上行锁,准备更新

    SELECT * FROM index_test WHERE t_id = 1 FOR UPDATE;

    b此时开始查询

    SELECT * FROM index_test WHERE t_id = 1 FOR UPDATE;

    产生读读互斥,b进入等待,等待a提交。

    a更新并提交

    UPDATE index_test SET key1 = key1 - 1 WHERE t_id = 1; 
    COMMIT;

    a提交后,b查出结果

     key1已经变成了0

    从而避免了库存超卖。

    死锁:

    和java的差不多。。。

    a:查询A,上锁A, 等查到后修改B,  然后提交

    b:查询B,上锁B, 等查到后修改A,  然后提交

    对于a,需要修改B才能提交事务,然后解锁A。

    对于b,需要修改A才能提交事务,然后解锁B。

    形成死锁。

    彼此占用钥匙。

    解决:kill掉其中一个线程。(图形界面比如sqlyog中直接点个x就完事了。。。不过linux开发有时要用名命令行的那种 - -)

  • 相关阅读:
    512M内存机器如何用好Mysql
    linux下查找文件和文件内容
    记“debug alipay”一事
    OFBiz中根据店铺获取产品可用库存的方法
    ubuntu中安装eclipse
    ubuntu中安装jdk
    ubuntu14.04中解压缩window中的zip文件,文件名乱码的解决方法
    apache将请求转发到到tomcat应用
    网站不能访问的原因
    birt报表图标中文显示为框框的解决方法
  • 原文地址:https://www.cnblogs.com/clamp7724/p/11824888.html
Copyright © 2011-2022 走看看