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开发有时要用名命令行的那种 - -)

  • 相关阅读:
    Java Web 网络留言板2 JDBC数据源 (连接池技术)
    Java Web 网络留言板3 CommonsDbUtils
    Java Web ConnectionPool (连接池技术)
    Java Web 网络留言板
    Java Web JDBC数据源
    Java Web CommonsUtils (数据库连接方法)
    Servlet 起源
    Hibernate EntityManager
    Hibernate Annotation (Hibernate 注解)
    wpf控件设计时支持(1)
  • 原文地址:https://www.cnblogs.com/clamp7724/p/11824888.html
Copyright © 2011-2022 走看看