MySQL-03.锁与事务

1.事务及其ACID属性

1.1.MySQL中的事务指什么?

        MySQL中的事务是由一组SQL语句组成的逻辑处理单元。
        数据库一般都会并发执行多个事务,多个事务可能会并发的对相同的一批数据进行增删改查操作。就会带来一系列的问题(脏写,脏读等)。,为了解决多事务的并发问题,数据库设计了事务隔离机制锁机制MVCC多版本并发控制隔离机制等来解决多事务并发问题。

1.2.事务的四个属性(ACID属性)

  • 原子性(Atomicity) :事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行(操作层面,所有操作要么全部成功要么全部失败)
  • 一致性(Consistent) :在事务开始和完成时,数据都必须保持一致状态(数据层面)
  • 隔离性(Isolation) :数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行(事务处理过程中的中间状态对外部是不可见的)
  • 持久性(Durable) :事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持

1.3.并发事务处理带来的问题

  • 脏写/更新丢失(Lost Update):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题:最后的更新覆盖了由其他事务所做的更新
  • 脏读(Dirty Reads)事务A读取到了事务B已经修改但尚未提交的数据,还在这个数据基础上做了操作。此时,如果B 事务回滚,A读取的数据无效,不符合一致性要求。
  • 不可重读(Non-Repeatable Reads)事务A内部的相同查询语句在不同时刻读出的结果不一致,不符合隔离性
  • 幻读(Phantom Reads)事务A读取到了事务B提交的新增数据,不符合隔离性

1.4.事务的隔离级别

“脏读”“不可重复读”“幻读” 都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决。数据库提供了一些几种隔离级别,来解决这些的问题。MySQL 默认的隔离级别是可重复读,一般的公司也默认使用该隔离级别。Spring 框架也可以使用参数来进行设置。如果设置了则使用框架默认隔离级别,未设置则使用数据库设置的隔离级别。

隔离级别脏读不可重复读幻读
读未提交(Read uncommitted)可能可能可能
读已提交(Read committed)不可能可能可能
可重复读(Repeatable read)不可能不可能可能
可串行化(Serializable)不可能不可能不可能

        数据库的事务隔离越严格,并发副作用越小,付出的代价也就越大。 比如串行化无论增删查改都会对数据进行加锁操作,在这期间,其他事务是无法对这些记录进行操作的。

#常看当前数据库的事务隔离级别
show variables like 'tx_isolation';
#设置事务隔离级别 后面加上对应的英文单词
set tx_isolation='REPEATABLE-READ'

2.锁

2.1.数据库中的锁是什么?

        计算机协调多个进程或线程并发访问某一资源的机制叫锁。
        在数据库中,除了传统的计算资源(如CPU、RAM、I/O等)的争用以外,**数据也是一种供需要用户共享的资源。**如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发 访问性能的一个重要因素。

2.2.锁分类

性能上:

  • 乐观锁(使用版本对比实现):每次对数据进行操作都会认为没有其他事务对该数据进行操作,仅在提交前进行比对,被修改则重新操作
  • 悲观锁:每次数据操作前都认为会有其他事务对其进行操作,而直接加锁

操作类型上:

  • 读锁(共享锁,S锁(Shared)):针对同一份数据,多个读操作可以同时进行而不会互相影响
  • 写锁(排它锁,X锁(eXclusive)):当前写操作没有完成前,它会阻断其他写锁和读锁
    读锁会阻塞写,但是不会阻塞读。而写锁则会把读和写都阻塞

数据操作粒度上:

  • 表锁每次操作直接锁住整张表。开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低; 一般用在整表数据迁移的场景
  • 行锁:**每次操作锁住一行数据。**开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度最 高。
#手动增加表锁(读锁或写锁)
lock table 表名称 read/write,表名称2 read/write;
#查看表上加的锁 
show open tables;
#删除表锁 
unlock tables;

MyISAM 和 InnoDB 对比:
        MyISAM在执行查询语句 SELECT 前,会自动给涉及的所有表加读锁,在执行update、insert、delete操作会自 动给涉及的表加写锁。 InnoDB在执行查询语句SELECT时(非串行隔离级别),不会加锁。但是update、insert、delete操作会加行 锁。
        Innodb存储引擎由于实现了行级锁,在锁定机制的实现方面所带来的性能损耗可能比表级锁定会要更高一些,但整体并发处理能力要远远优于 MYISAM 的表级锁定的。当系统并发量高的时候,InnoDB 的整体性能和 MYISAM 相比就会有比较明显的优势了。 但 InnoDB 的行级锁定同样也有其脆弱的一面,当我们使用不当的时候,可能会让InnoDB 的整体性能表现 不仅不能比 MYISAM 高,甚至可能会更差。

间隙锁(Gap Lock)
        间隙锁,锁的就是两个值之间的空隙。间隙锁 在某些情况下可以解决幻读问题。
        假设某张表 Student 中有记录如下5条记录:

idname
1张三
2李四
3王五
10赵二
20马六

        那么这张表就可以划分为三个间隙区间 (3,10)、(10,20)、(20,+∞),假如在 Session_1 下面执行 update Student set name = ‘刘一’ where id > 8 and id < 18;,则其他 Session 没法在这个范围所包含的所有行记录(包括间隙行记录)以及行记录所在的间隙里插入或修改任何数据,即id在 (3,20] 区间都无法修改数据。假如在 Session_1 下面执行 update Student set name = ‘刘一’ where id > 8 and id < 21;,则其他 Session 没法在这个范围所包含的所有行记录(包括间隙行记录)以及行记录所在的间隙里插入或修改任何数据,即id在 (3,+∞] 区间都无法修改数据。注意间隙锁在可重复读隔离级别下才会生效。

临键锁(Next-key Locks):
        行锁与间隙锁的组合。像上面那个例子里的这个(3,20]的整个区间可以叫做临键锁。

无索引行锁会升级为表锁:
        InnoDB的行锁是针对索引加的锁,不是针对记录加的锁。并且该索引不能失效,否则都会从行锁升级为 表锁

行锁分析:

#通过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况
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:系统启动后到现在总共等待的次数

查看INFORMATION_SCHEMA系统库锁相关数据表:

#查看事务
select * from INFORMATION_SCHEMA.INNODB_TRX;
#查看锁
select * from INFORMATION_SCHEMA.INNODB_LOCKS;
#查看锁等待
select * from INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
#释放锁,trx_mysql_thread_id 可以从 INNODB_TRX 表里查看到
kill trx_mysql_thread_id
#查看锁等待详细信息
show engine innodb status\G;

锁优化建议

  • 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁
  • 合理设计索引,尽量缩小锁的范围
  • 尽可能减少检索条件范围,避免间隙锁
  • 尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的sql尽量放在事务最后执行
  • 尽可能低级别事务隔离
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值