mysql基础之-mysql锁和事务(七)
0x01
MySQL锁:
执行操作时施加锁的模式
读锁:用户在读的时候施加的锁,为防止别人修改,但是用户可以读,还被称为共享锁 不会对其他用户进行阻塞
理解: ----->(这里的不阻塞,是可以让用户读(即-不对用户读进行阻塞),但是不能让用户写入数据,是会阻塞写入的数据,除非解锁)
显示锁(表级锁):
lock tables:施加锁
LOCK TABLES
tbl_name lock_type
[, tbl_name lock_type] ...
锁的类型
READ | WRITE
unlock tables:解锁
实例:
原表中数据,如下:
对表进行读锁,用其他用户进行查询表内容依然可以进行查询,如下
但是此时若要对表进行写入数据的操作那么 会被阻塞,如下:
若要不被阻塞,那么就要解锁,如下:
写锁:独占锁,排它锁。其他用户不能读,不能写 会对其他用户进行阻塞,只有阻塞解除了,其他用户才能读 (阻塞的)
实例:
对表进行写锁
对表进行解锁便能查询
锁粒度:
表锁:table lock
锁定了整张表
行锁:row lock
锁定了需要的行
粒度越小,开销越大,但并发性越好:
粒度越大,开销越小,但并非性越差;
锁的实现位置:
MySQL锁:可以手动使用,可以使用显示锁
存储引擎锁:自动进行的(隐式锁),
0x02
InnoDB存储引擎也支持另外一种显示锁(锁定挑选出的部分行,行级锁)
select .... lock in share mode
select .... for update
实例:
首先这种行级锁是适用于innodb存储引擎
若不是innodb存储引擎,则需要更改,当然,大的实际的生产环境数据很庞大的环境,是不建议更改随便更改存储引擎,我这是测试,所有更改为innodb存储引擎
alter table classes engine 'innodb';
如下所示已经更改为innodb存储引擎
show table status like 'classes'\G;
设置行级锁模式
select * from classes where classid <= 5 lock in share mode;
PS:在以上行级锁,只能在sql语句执行的时候实现锁的机制,sql语句执行完毕,便不再起作用,所有这里无法演示其效果
0x03
事务:Transaction
事务就是一组原子性的查询语句,也即将多个查询当作一个独立的工作单元。
理解事务:就是将一系列的sql语句当作“一句”来执行的一种机制——该系列语句要么全部执行成功,要么一个都不执行。
事务实际应用:我们经验中的一个“操作”,其实常常对应着数据库(表)的2个或2个以上的操作,此时就应该让此2个操作具有“整体性”。比如网银汇款,其实是将一个储户中的钱减少一个数目,再将另一个储户的钱增加一个数目。如果只做完了前者,后者因为某种原因没有做完就出错了,此时就悲剧了。
ACID测试:能够满足ACID测试就表示其支持事务,或兼容事务
A:Atomicity,原子性,一个事务必须被分为不可分割的单元,要么都执行要么都不执行都执行
C:Consistency,一致性,从一个一致性状态转到另外一个一致性状态,而不会导致数据丢失
I:Isolaction,隔离性。一个事务的所有修改操作在提交前对其他事务时不可见的
D: Durability, 持久性,一旦事务得到提交,其所做的修改会永久有效
启动事务
start transaction;
事务提交
commit
实例:
开启事务,删除数据。
上述删除数据,但是没有提交,commit,可以通过回滚,进行恢复,如下:
事务回滚
rollback
如若按照上述进行删除数据,但是进行提交,commit,那么数据就真的被删除了,不能再回滚
SAVEPOINT 控制回滚的位置
SAVEPOINT identifier
ROLLBACK [WORK] TO [SAVEPOINT] identifier
实例:
再设置一个回滚点,如下:
尝试回滚对应回滚的位置:
0x04
如何没有显式启动事务,每个语句都会当作一个默认的事务,其执行完成会被自动提交 ---mysql的默认功能
show global variables like '%commit%'; ------ 为 ‘ON’ 表示自动提交
select @@global.autocommit ---- 为 数字 ‘1’ 表示自动提交
关闭其自动提交功能 --- 设置为 ‘0’ --如下
set global autocommit = 0
注意 关闭自动提交,请记得手动启动事务,应记得手动提交
安全性越高,并发性越低
隔离级别:
READ UNCOMMITTEND(读未提交),不可重复读,幻读 ---- 脏读 -> 能够读取别人尚未提交的数据叫脏读 -- 用户没有提交数据,但是别的用户能查询看到数据-读未提交
READ COMMITTEND(读提交) 用户没有提交数据,查询看不到数据--- 读提交
REPEATABLE READ (可重读) ---mysql默认的隔离级别
SERIALIZABLE(可串行化)强制事务的串行执行避免了幻读;性能极低
所有事务只支持innodb存储引擎
查看mysql的事务隔离级别
show global variables like '%iso%'
select @@global.tx_isolation
实例:
更改事务隔离级别为读未提交:
set global tx_isolation='read-uncommitted';
上述设置完成之后,因为是全局环境,所有要重新登录mysql进行测试,
回滚之后,发现查询脏读的数据,是一样的,此时验证了不可重复读。
实例:
更改事务隔离级别为读提交:
set global tx_isolation='read-committed';
开启事务,进行删除数据测试
此时在没有提交的情况下,在另一个会话中开启事务
start transaction;
进行查询,如下:
此时在提交的情况下,在另一个会话中查看数据,如下:
上述没有脏读。
实例:
更改事务隔离级别为REPEATABLE READ (可重读):
set global tx_isolation='repeatable-read';
开启事务,进行删除数据测试
此时在没有提交的情况下,在另一个会话中开启事务
start transaction;
进行查询,如下:
发现没有读到被删除后的数据,没有脏读。
当提交之后,发现还是看不到被删除的数据
上述是进行删除操作的用户,做了commit操作,她自己能够查看删除后的数据,但是其他用户并没有看到被删除后的数据,此时,其他用户需要自己commit才能查看被删除的数据,如下:
这就是REPEATABLE READ 可重读性
实例:
更改事务隔离级别为SERIALIZABLE(可串行化)强制事务的串行执行避免了幻读;性能极低
set global tx_isolation='serializable';
分别开启两个会话重新登录mysql开启事务,其中一个用户做删除操作,发现无法操作,一直卡着。
但是,如果两个用户都删除操作,会有其中一个用户操作成功,如下:
SERIALIZABLE(可串行化)强制事务的串行执行避免了幻读;性能极低
建议:对事物要求不特别严格的场景下,可以使用读提交
MVCC:多版本并发控制
每个事务启动时,InnoDB会为每个启动的事务提供一个当下时刻的快照
为实现此功能,InnoDB会为每个表提供两隐藏的字段,一个用于保存行的创建时间,一个用于保存行的失效时间
里面存储的系统版本号
旨在两个隔离级别下有效:read committed和repeatable read