• mysql锁简谈


    1.mysql锁,
    作用:解决因资源共享而造成的并发问题。
    实例:买最好一件衣服X
    A: X 买: X加锁----->试衣服……下单……付款……打包….------>X解锁
    B: X 买: 发现X已被加锁,等待X解锁,X已售空

    分类 :
    操作类型:
    A.读锁(共享锁):对同一个数据(衣服),多个读操作可以同时进行,互不干扰
    B.写锁(互斥锁):如果当前写操作没有完毕(买衣服的一系列操作),则无法进行其他的读操作,写操作。

    操作范围:
    A.表锁:一次性对一张表整体加锁.
    如:MYISAM存储引擎使用表锁,开销小,加锁快,无死锁;
    但锁的范围大,容易发生锁冲突,并发度低;

    B.行锁:一次性对一条数据加锁
    如:INNODB存储引擎使用行锁,开销大,加锁慢,容易出现死锁;
    但锁的范围较小,不易发生锁冲突,并发度高(很小概率发生高并发问题:脏读,幻读,不可重复读,丢失更新等)


    实例:
    表锁: 自增操作mysql/sqlserver支持,Oracle需要借助于序列来实现自增
    Create table tablelock
    (
    Id int primary key auto_increment,
    Name varchar(20)
    )engine myisam;

    Insert into tablelock(name) values('a1')
    Insert into tablelock(name) values('a2')
    Insert into tablelock(name) values('a3')
    Insert into tablelock(name) values('a4')
    Insert into tablelock(name) values('a5')

    查看加锁的表: show open tables; desc emp;查表结构

    增加锁: locak table 表1 read/write , 表2 read/write , …..
    回话1:session
    加读锁:locak table tablelock read;
    select * from tablelock; -----读,可以
    delete from tablelock where id=1;-------写(增删改),不可以

    Select * from emp;-----读,不可以
    Delete from emp where eno=1;------写,不可以

    总结:会话1如果给A表加了读锁,则当前会话只能对A表进行读操作,其他表都不能操作

    会话2(其它会话):
    Select * from tablelock;-------读,可以
    Delete from tablelock where id=1;-----写,会“等待”会话1解锁为止

    Select * from emp;-------读,可以
    Delete from emp where eno=1;--------写,可以

    总结:会话1给A表加了锁,其它会话的操作:
    A.可以除了A表的其它表进行读,写操作
    B.对A表:读,可以,写要等待释放锁

    释放锁:会话1执行, unlock tables;



    2.加写锁:
    会话1:
    lock table tablelock write;

    当前会话1,可以对加了锁的表进行任何操作(增删改查),但是不能操作(增删改查)其它表

    其它会话2,对会话1中加写锁的表,可以进行增删改查的前提是:等待会话1释放写锁



    MySQL表极锁的锁模式
    MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作 (DML)前,会自动给涉及的表加写锁。
    所以对MyISAM表进行操作,会有以下情况:
    A.对MyISAM表的读操作(加读锁),不会阻塞其它进程(会话)对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其它进程的写操作。
    B.对MyISAM表的写操作(加写锁),会阻塞其它进程(会话)对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。



    分析表锁定:
    查看哪些表加了锁:show open tables;----1代表被加了锁
    分析表锁定的严重程度:show status like ‘%table%’;
    Table_locks_immediate:即可能获取到的锁数
    Table_locks_waited:需要等待的表锁数(如果该值越大,说明存在越大的锁竞争)
    一般建议Table_locks_immediate/Table_locks_waited>5000,则建议采用InnoDB引擎,否则用MyISAM引擎


    行表(InnoDB)
    Create table linelock(
    Id int(5) primary key auto_increment,
    Name varchar(20)
    )engine=innodb;
    Insert into linelock (name) values('1');
    Insert into linelock (name) values('2');
    Insert into linelock (name) values('3');
    Insert into linelock (name) values('4');
    Insert into linelock (name) values('5');
    ------mysql默认自动commit;Oracle默认不会自动commit;

    为了研究行锁,暂时关闭commit;set autocommit=0;以后每条都要commit

    会话1:写操作
    Insert into linelock values(6,'a6'); -----------关闭commit后,在缓存里,commit后才生效
    会话2:写操作同样的数据
    Update linelock set name='ax' where id=6;---------想更新id为6的数据,执行时出现被锁状态,直到其它会话释放(commit)后才能操作(行锁)
    提交:commit;丢弃:rollback;

    对行锁情况:
    1.如果会话x对数据a进行DML操作(研究时关闭了自动commit的情况下),则其它会话必须等到会话x结束事务(commit/rollback)后,才能对数据a进行操作。
    2.表锁 是通过unlock tables; ,也可以通过事务解锁。行锁 是通过事务解锁。

    行锁,一次锁一行数据,因此,如果操作的是不同数据,则不干扰。


    3.行锁的注意事项:
    A.如果没索引,则行锁会转为表锁
    Show index from linelock;
    Alter table linelock add index idx_linelock_name(name);

    会话1:写操作
    Update linelock set name='ai' where name='3';
    会话2:写操作,不同的数据
    Update linelock set name='aix' where name='4';

    会话1:写操作
    update linelock set name='ai' where name=3;
    会话2:写操作,不同数据
    update linelock set name='aix' where name=4;

    -------->可以发现,数据被阻塞了(加锁)
    -------->原因:如果索引类 发生了类型转换,则索引失效。因此此次操作,会从行锁转为表锁。

    B.行锁的一种特殊情况:间隙锁:值在范围里,但却不存在。
    此时linelock表中,没有id=7的数据
    Update linelock set name='x' where id>1 and id<9;
    mysql会自动给间隙加锁---->间隙锁,给id=7的数据加间隙锁(行锁)。
    行锁:如果有where,则实际加锁的范围就是where后面的范围(不是实际的值)

    行锁:innodb默认采用行锁
    缺点:比表锁性能消耗大
    优点:并发能力强,效率高
    建议:高并发用innodb,否则用myisam

    分析:show status like '%innodb_row_lock%';

    Innodb_row_lock_current_waits: 当前正在等待锁的数量
    Innodb_row_lock_time: 等待总时长,从系统启动到现在一共等待的时间
    Innodb_row_lock_time_avg:平均等待时间
    Innodb_row_lock_time_max:最长等待时间
    Innodb_row_lock_waits: 系统启动到现在一共等待的次数

    查询行锁:

    关闭commit自动提交:
    set autocommit;
    start transaction;
    begin;

    for update对query语句加锁
    Select * from linelock where id=2 for update


    4.主从复制:
    优点:负载均衡
    失败迁移

    Windows:mysql 主
    Linux:mysql 从
    (版本最好相近或相同)

    图形客户端工具
    SQLyog, Navicat

    如果要远程连接数据库,则需要授权远程访问。
    Windows:安装时选择可以远程访问
    Linux:GRANT ALL PRIVILEGES ON *.* TO 'root' @'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
    FLUSH PRIVILEGES;
    关闭防火墙:service iptables stop

    主机Windows192.168.2.2:授权那个数据库作为自己的slave
    GRANT REPLICATION slave ,reload, super ON *.* TO 'root'@'192.168.2.%' IDENTIFIED BY 'root';
    fulsh privileges;
    show master status;

    从机linux:授权那个数据库作为自己的master
    CHANGE MASTER TO MASTER_HOST ='192.168.2.2',MASTER_USER='root', MASTER_PASSWORD='root' ,MASTER_PORT=3306,
    master_log_file='mysql-bin.000002', master_log_pos=667;



    5.主从复制:
    同步的核心:二进制文件binary log
    对数据库的增删改查的操作都会备份到二进制文件里
    从数据库的I/O线程会从主数据库读二进制文件
    Relay log通过sql线程写到从数据库

    1.master将改变的数记录在本地的二进制日志中(binary log):
    该过程称之为二进制日志事件
    2.slave将master的binary log拷贝到自己的relay log(中继日志文件)中
    3.中继日志事件,将数据读取到自己的数据库之中

    mysql主从复制是异步,串行化的,有延迟的

    master:slave=1:n

    配置:
    Windows:主mysql,my.ini
    Linux:从mysql,my.cnf

    配置前,为了无误,先将各防火墙,权限(远程访问)处理好

    主mysql,my.ini配置文件中:
    [mysqld]下,server-id=1
    log-bin="mysql安装目录/data/mysql-bin" ----二进制文件,注意是/,不是
    log-error="mysql安装目录/data/mysql-error" ---错误记录文件
    binlog-ignore-db=mysql ------主从同步时,忽略的数据库
    binlog-do-db=test ------主从同步时,同步哪些数据

    Windows主mysql授权那台从计算机
    GRANT REPLICATION slave ,reload, super ON *.* TO 'root'@'192.168.2.%' IDENTIFIED BY 'root';
    fulsh privileges;
    show master status; ----查看主数据库的状态
    File ,Position , Binlog_Do_DB , Binlog_Ignore_DB
    Mysql-bin.000001 , 575 , test , mysql

    重启后二进制文件才有mysql-bin,mysql-error
    File , Position(107)要变,每次在左主从同步前,需要观察主机状态的最新值

    从mysql, my.cnf配置文件中:
    [mysqld]下,server-id=2
    log-bin=mysql-bin
    replicate-do-db=test

    linux中的从mysql授权那台主计算机
    从机linux:授权那个数据库作为自己的master
    CHANGE MASTER TO MASTER_HOST ='192.168.2.2',MASTER_USER='root', MASTER_PASSWORD='root' ,MASTER_PORT=3306,
    master_log_file='mysql-bin.000001', master_log_pos=107;

    如果报错:This operation cannot be performed with a running slave ; run STOP SLAVE first
    第一次不报错,第二第三次出这个错,
    先STOP SLAVE; 再执行上面从mysql授权语句

    开启主从同步:
    从机Linux:start slave ;
    检验状态: show slave status G
    主要观察2个,slave_sql_running,slave_io_running , 要都是yes
    如果不是yes,则看下方的日志 last_io_error,主从使用了相同的server-id,
    检查:在主从中分别查看server-id:show variables like '%server_id%' ; 发现确实都是1,但配置时是1,2,版本bug
    Windows:5.5.56 ;Linux:5.5.58,可能5.5.58版本兼容性问题,或者是版本不同问题
    解决:文件改不行,现在用全局变量改:set global server_id=2 ; (linux) , 设置了后关闭再开启


    演示:主mysql在test数据库中新增表,插入数据,从mysql自动同步数据了.自此主从同步成功。


  • 相关阅读:
    第一章——第二节 启动模式
    Android 展示键盘时候布局被修改的问题
    JAVA混型和潜在类型机制
    第一章——Activity的生命周期
    android 程序中禁止屏幕旋转和重启Activity
    项目知识—九
    项目知识——八
    项目知识——七
    Drawable复习—第六章
    项目知识(六)
  • 原文地址:https://www.cnblogs.com/mingdeng3000/p/11941525.html
Copyright © 2020-2023  润新知