Mysql(三):锁与事务

1.MySql中的锁

  • 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如 OLAP (Online analytical processing,联机分析处理)系统。
  • 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些OLTP(On-Line Transaction Processing:联机事务处理)系统。
  • 页面锁(gap 锁,间隙锁):开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

2.MyISAM 锁

表共享读锁(Table Read Lock)

  • 语法:lock table 表名 READ,unlock tables;解锁
lock table testmysam READ 
  • 读锁,对 MyISAM 表的读操作,不会阻塞当前 session/其他session对同一表的读请求,但会阻塞对同一表的写请求;当前session更新或访问读其他表都会提示错误(查询被锁的表不能使用别名,否则也会被锁)

表独占写锁(Table Write Lock)

  • 语法:lock table 表名 WRITE;unlock tables;解锁
lock table testmysam WRITE
  • 写锁,对 MyISAM 表的写操作,则会阻塞其他会话对同一表的读和写操作,当前 session 可以对本表做 CRUD,但对其他表进行操作会报错

3.InnoDB 锁

共享锁

  • 又称读锁。当一个事务对某几行上读锁时,允许其他事务对这几行进行读操作,但不允许其进行写操作,也不允许其他事务给这几行上排它锁,但允许上读锁。

  • 语法:select * from 表where 条件lock in share mode;

排它锁

  • 又称写锁。当一个事务对某几个上写锁时,不允许其他事务写,但允许读。更不允许其他事务给这几行上任何锁。
  • 语法:select * from 表where 条件for update;

注意

1.两个事务不能锁同一个索引的同一部分值,另一个等待。

2.insert ,delete , update 在事务中都会自动默认加上排它锁。即使后面没加for update

3.行锁必须有索引才能实现,否则会自动锁全表,那么就不是行锁了。

排查

查看锁以及被锁数据:

mysql5.6&mysql5.7:

select * from information_schema.INNODB_LOCKS;

Mysql8:

SELECT * from performance_schema.data_locks;

查看具体要kill的线程号:

mysql5.7&mysql8:

select * from sys.innodb_lock_waits;

mysql5.6:

SELECT
r.trx_id waiting_trx_id,r.trx_mysql_thread_id waiting_thread,
r.trx_query waiting_query,
b.trx_id blocking_trx_id,
b.trx_mysql_thread_id blocking_thread
FROM
information_schema.innodb_lock_waits w
INNER JOIN
information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
INNER JOIN
information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;

4.查看支持事务的存储引擎

show engines; --只有InnoDB

show variables like '%storage_engine%'; --查看默认存储引擎

show create table 表名; --查看某张表使用的存储引擎

5.事务特性

原子性(atomicity)

一个事务必须被视为一个不可分割的最小单元,整个事务中的所有操作要么全部提交成功,

要么全部失败,对于一个事务来说,不可能只执行其中的一部分操作

一致性(consistency)

一致性是指事务将数据库从一种一致性转换到另外一种一致性状态,在事务开始之前和事务

结束之后数据库中数据的完整性没有被破坏

持久性(durability)

一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,已经提交的

修改数据也不会丢失

隔离性(isolation)

一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,已经提交的

修改数据也不会丢失

  • 未提交读(READ UNCOMMITED)脏读
  • 已提交读(READ COMMITED)不可重复读
  • 可重复读(REPEATABLE READ)
  • 可串行化(SERIALIZABLE)
show variables like '%tx_isolation%'; --默认RR可重复读

未提交读(READ UNCOMMITED)

会引起脏读,不可重复读,幻读

set SESSION TRANSACTION ISOLATION LEVEL read UNCOMMITTED;

已提交读(READ COMMITED)

解决脏读,会引起不可重复读,幻读

set SESSION TRANSACTION ISOLATION LEVEL read committed;

可重复读(REPEATABLE READ)

解决不可重复读,会引起幻读

mysql默认隔离级别,通过间隙锁解决幻读问题

set SESSION TRANSACTION ISOLATION LEVEL repeatable read;

可串行化(SERIALIZABLE)

解决幻读

set SESSION TRANSACTION ISOLATION LEVEL serializable;

间隙锁(gap锁)

select @@tx_isolation;

create table t_lock_1 (a int primary key);

insert into t_lock_1 values(10),(11),(13),(20),(40);

对于主键索引

一个会话中:

begin;

select * from t_lock_1 where a <= 13 for update;

另一个会话中

insert into t_lock_1 values(21) --成功

insert into t_lock_1 values(19) --阻塞

where id <=x for update;

mysql5.7中:扫描到值x在表中的下一个值为止,都不可改,(-无穷,下一个值]

mysql8中:扫描到当前值x 都不可改

where id in (a,b) for update;

mysql5.7中:整张表不可改

Mysql8.0中:只有in条件中的数据不可改

非主键上的索引:

create table t_lock_2 (a int primary key,b int, key (b));

insert into t_lock_2 values(1,1),(3,1),(5,3),(8,6),(10,8);

一个会话中:

BEGIN;

select * from t_lock_2 where b=3 for update;

另一个会话中:

select * from t_lock_2 where a = 5 lock in share mode; -- 不可执行,因为a=5 上有一把记录锁

insert into t_lock_2 values(4, 2); -- 不可以执行,因为b=2 在(1, 3]内

insert into t_lock_2 values(6, 5); -- 不可以执行,因为b=5 在(3, 6)内

insert into t_lock_2 values(2, 0); -- 可以执行,(2, 0)均不在锁住的范围内

insert into t_lock_2 values(6, 7); -- 可以执行,(6, 7)均不在锁住的范围内

insert into t_lock_2 values(9, 6); -- 可以执行

insert into t_lock_2 values(7, 6); -- 不可以执行


锁住值x对应的主键id对应不可改

非主键索引锁得是[上一个值,下一个值]

6.事务语法

开启事务

begin;
START TRANSACTION;
begin work;

事务回滚

rollback;

事务提交

commit;

还原点

savepoint

show variables like '%autocommit%'; --自动提交事务是开启的

set autocommit=0;

insert into testdemo values(5,5,5);

savepoint s1;

insert into testdemo values(6,6,6);

savepoint s2;

insert into testdemo values(7,7,7);

savepoint s3;

select * from testdemo

rollback to savepoint s2

rollback

你可能感兴趣的:(db)