前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >高性能MySql学习笔记1——锁、事务、隔离级别

高性能MySql学习笔记1——锁、事务、隔离级别

作者头像
程序员小王
发布2018-04-13 11:15:42
7770
发布2018-04-13 11:15:42
举报
文章被收录于专栏:架构说

提问: 事物的概念什么是脏读?不可重复读

为什么需要锁?

因为数据库要解决并发控制问题。在同一时刻,可能会有多个客户端对Table1.rown进行操作,比如有的在读取该行数据,其他的尝试去删除它。为了保证数据的一致性,数据库就要对这种并发操作进行控制,因此就有了锁的概念。

锁的分类

从对数据操作的类型(读\写)分

读锁(共享锁):针对同一块数据,多个读操作可以同时进行而不会互相影响。

写锁(排他锁):当当前写操作没有完成前,它会阻断其他写锁和读锁。

从锁定的数据范围分

表锁

行锁

为了尽可能提高数据库的并发度,每次锁定的数据范围越小越好,理论上每次只锁定当前操作的数据的方案会得到最大的并发度,但是管理锁是很耗资源的事情(涉及获取,检查,释放锁等动作),因此数据库系统需要在高并发响应和系统性能两方面进行平衡,这样就产生了“锁粒度(Lock granularity)”的概念

锁粒度(Lock granularity)

表锁:管理锁的开销最小,同时允许的并发量也最小的锁机制。MyIsam存储引擎使用的锁机制。当要写入数据时,把整个表都锁上,此时其他读、写动作一律等待。在MySql中,除了MyIsam存储引擎使用这种锁策略外,MySql本身也使用表锁来执行某些特定动作,比如alter table.

行锁:可以支持最大并发的锁策略。InnoDB和Falcon两张存储引擎都采用这种策略。

MySql是一种开放的架构,你可以实现自己的存储引擎,并实现自己的锁粒度策略,

不像Oracle,你没有机会改变锁策略,Oracle采用的是行锁。

事务(Transaction)

从业务角度出发,对数据库的一组操作要求保持4个特征:

Atomicity:原子性

Consistency:一致性,

Isolation:隔离性

Durability:持久性

为了更好地理解ACID,以银行账户转账为例:

1 START TRANSACTION;

2 SELECT balance FROM checking WHERE customer_id = 10233276; 3 UPDATE checking SET balance = balance - 200.00 WHERE customer_id = 10233276; 4 UPDATE savings SET balance = balance + 200.00 WHERE customer_id = 10233276; 5 COMMIT;

原子性:要么完全提交(10233276的checking余额减少200,savings 的余额增加200),要么完全回滚(两个表的余额都不发生变化) 一致性:这个例子的一致性体现在 200元不会因为数据库系统运行到第3行之后,第4行之前时崩溃而不翼而飞,因为事物还没有提交。 隔离性:允许在一个事务中的操作语句会与其他事务的语句隔离开,比如事务A运行到第3行之后,第4行之前,此时事务B去查询checking余额时,它仍然能够看到在事务A中被减去的200元,因为事务A和B是彼此隔离的。在事务A提交之前,事务B观察不到数据的改变。 持久性:这个很好理解。 事务跟锁一样都会需要大量工作,因此你可以根据你自己的需要来决定是否需要事务支持,从而选择不同的存储引擎。

隔离级别(Isolation Level)

SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。 Read Uncommitted(读取未提交内容)

在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。

本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。

读取未提交的数据,也被称之为脏读(Dirty Read)。 Read Committed(读取提交内容)

这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。 Repeatable Read(可重读)

这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。

简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。

InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。

Serializable(可串行化) 这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。例如:

脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。

不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。

幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。

在MySQL中,实现了这四种隔离级别,分别有可能产生问题如下所示:

mysql默认级别 可重复度 REPEATABLE-READ

如何发现数据发生了变化:

脏读: 别人不提交 我发现不了数据发生改变

不重复读: 既是别人提交了 自己不提交 仍然发现不了数据发生变化

下面进行一下测试:

Time

Session 1

Session 2

T1

set autocommit=0;

set autocommit=0;

T2

mysql> select * from tmp_test; +——+———+| id | version |+——+———+| 1 | 1 |+——+———+1 row in set (0.00 sec)

T3

mysql> update tmp_test set version=2 where id=1; Query OK, 1 row affected (0.02 sec)Rows matched: 1 Changed: 1 Warnings: 0mysql> select * from tmp_test;+——+———+| id | version |+——+———+| 1 | 2 |+——+———+1 row in set (0.00 sec)

T4

mysql> select * from tmp_test; +——+———+| id | version |+——+———+| 1 | 1 |+——+———+1 row in set (0.00 sec)【说明】Session 2未提交,看到数据不变,无脏读。

T5

commit;

T6

mysql> select * from tmp_test; +——+———+| id | version |+——+———+| 1 | 1 |+——+———+1 row in set (0.00 sec)【说明】Session 2已经提交,还是看到数据不变,即可以重复读。

T7

commit;

T8

mysql> select * from tmp_test; +——+———+| id | version |+——+———+| 1 | 2 |+——+———+1 row in set (0.00 sec)【说明】提交事务,看到最新数据。

T9

mysql> insert into tmp_test values(2,1); Query OK, 1 row affected (0.00 sec)mysql> select * from tmp_test;+——+———+| id | version |+——+———+| 1 | 2 || 2 | 1 |+——+———+2 rows in set (0.00 sec)mysql> commit;Query OK, 0 rows affected (0.00 sec)

T10

mysql> select * from tmp_test; +——+———+| id | version |+——+———+| 1 | 2 |+——+———+1 row in set (0.00 sec)【说明】Session 2的insert事务已经提交,看到的数据和T8的时候一样,即未发生幻象读。

T11

mysql> commit; Query OK, 0 rows affected (0.00 sec)mysql> select * from tmp_test;+——+———+| id | version |+——+———+| 1 | 2 || 2 | 1 |+——+———+2 rows in set (0.00 sec)【说明】事务提交,看到最新数据。

参考

1 http://blog.csdn.net/dong976209075/article/details/8802778

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-09-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Offer多多 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么需要锁?
  • 锁的分类
    • 从对数据操作的类型(读\写)分
      • 从锁定的数据范围分
      • 锁粒度(Lock granularity)
      • 事务(Transaction)
      • 隔离级别(Isolation Level)
      相关产品与服务
      云数据库 SQL Server
      腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档