二、读写锁(锁粒度)

1、共享锁=读锁:互不干扰、相互不阻塞,多个客户在同一时刻可以同时读取同一个资源。

2、排他锁=写锁:一个写锁会阻塞其他的写锁和读锁。出于安全考虑,确保在给定的时间里只有一个用户能执行写入,并防止其他用户读取正在写入的同一资源。

 

锁问题:锁的各种操作,包括获得锁、检查锁是否已经解除、释放锁等都会增加系统的开销。如果系统花大量的时间来管理锁,而不是读取数据,那么系统的性能可能会因此收到影响。锁定的数量越少,系统的并发程度越高,只要相互之间不发生冲突。

表锁:基本的锁策略,并且是开销最小的策略。会锁定整张表。一个用户对表进行写操作(插入、删除、更新)前需要先获得锁。

行级锁:可以最大程度的支持并发处理(InnoDB XtraDB等)行级锁只在存储引擎层实现。带来了最大的锁开销。

3、事务:一组原子性的SQL查询,一个独立的工作单元。事务内的语句要么全部执行成功,要么全部执行失败。需要更强的CPU处理能力比没有事务的。

ACID

原子性(atomicity):一个事务必须被视为一个不可分割的最小工作单元

一致性(consistency):数据库总是从一个一致性的状态转换到另一个一致性的状态。

隔离性(isolation):一个事务所做的修改在最终提交以前,对其他事务不可见。

持久性(durability):一旦事务提交,则其所做的修改就会永久保存到数据库中。

 

事务SQL例子:银行例子转钱

start transaction;
select balance from checking where customer_id = 100234;
update checking set balance = balance -200.00 where customer_id = 100234;
update saving set balance = balance -200.00 where customer_id = 100234;
commit;

 

隔离级别:每种事务级别都规定了一个事务中所做的修改,那些在事务内和事务间是可见的,那些是不可见的。较低的级别隔离通常可以执行更高的并发,系统的开销也更低。

1)为提交读:read uncommitted :事务中的修改即使没有提交,也对其他的事务也都是可见的。事务可以读取为提交的数据===》问题脏读

2)提交读 read commited (mysql 默认隔离级别不是这个) :一个事务开始到提交之前,所做的任何修改对其他的事务都是不可见的。 ===》 不可重复的读 可能读取到不一样的结果

3)可重复读 repeatable read:j解决了脏读问题,级别保证了在同一事务中多次读取同样记录的结果是一致的。

但无法解决幻读。 是mysql 的默认事务隔离级别

幻读:中的是当某个事务在读取某个范围的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行。InnoDB 和XtraDB村粗引擎通过多版本并发控制解决了幻读的问题。

4)可串行化serializable :是最高的隔离级别。会在读取的每一行都加锁。可能导致大量的超时和锁争用的问题。在非常需要保持数据的一致性而且可以接受并发的情况下才考虑采用该级别。

 

死锁:指两个或者多个事务再同一资源上相互占用,并请求锁定对方占用的资源,导致恶性循环。

死锁检测、死锁超时机制、死锁回滚算法。死锁发生后:只有部分或者完全回滚其中一个事务,重新执行因斯多回滚的事务即可。

 

4、MySQL 中的事务

Mysql 提供两种事务型的存储引擎:InnoDB 和NDB Cluster ;

Mysql 默认采用自动提交模式(AUTOCOMMIT)。

Mysql 能够识别所有的4个 ANSI 隔离级别,InnoDB引擎也支持所有的隔离级别。

5、多版本并发控制(MVCC)

MySQL的大多数事务型存储引擎实现的都不是简单的行级锁。MVCC是行级锁的一个变种。

InnoDB 的MVCC 是通过在每行记录后面保存两个隐藏的列来实现的。这两列一个保存行的创建时间、一个保存行的过期时间存储的并不是实际的时间只值,是系统的版本号。每开始一个新的事务,系统的版本好都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的记录的版本号进行比较。

repeatable:

Select

InnoDB 会根据下面两个条件检查每行记录:

a:InnoDB只查找版本早于当前事务版本的数据行(行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。

b:行的删除版本要么为定义,要么大于当前事务版本号。这样可以确保事务读取到的行,在事务开始之前未被删除

只有符合上面两个条件才能返回作为查询结果。

Insert

InnoDB为新插入的每一行,保存当前系统版本号作为行版本号。

Delete

InnoDB为删除的每一行,保存当前系统版本号作为删除标识。

Update

InnoDB为新插入的每一行,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。

保存这两个版本号,使得大多数操作都可以不用加锁,使得读数据操作简单,性能很好。

 

MVCC 只在repeatable read 和read commited 两个隔离级别下工作。其他两个都不兼容

因为read uncommited 总是读取最新的数据行,serializable 则会对所有读取的都加锁。

6、存储引擎

mysql> show table status like 't_user';

上面命令可以查看表结构的有关信息

1)InnoDB 存储引擎是mysql默认事务引擎,使用最广泛、也是最重要的,他被设计用来处理大量的短期事务。默认级别repeatable read,并通过间隙锁策略防止幻读的出现。表是基于聚簇索引建立的。支持热备份。其他的引擎不支持。

2)MyISAM