一,事务
1,什么是事务
transactions,一个事务里可以包含多条sql语句,这些操作要么全部执行,要么全部不执行。
2,事务的4大特征ACID
通常称为ACID特征(首字母)
1)原子性
#事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
2)一致性
#事务应确保数据库的状态从一个一致状态转变为另一个一致状态,例如转账行为中,一个人减了10元,另外一个人就应该加上这10元,而不能是5元。
#其他一致状态的含义是数据库中的数据应满足完整性约束,例如字段约束不能为负数,事务执行完毕后的该字段也同样不是负数
3)隔离性
#多个事务并发执行时,一个事务的执行不应影响其他事务的执行
4)持久性
#一个事务一旦提交,他对数据库的修改应该永久保存在数据库中。
3,事务的3种运行模式
隐式 == 自动
显式 == 手动
1. 自动提交事务(隐式开启、隐式提交)
2. 显式事务(显式开启、显式提交)
3. 隐式事务(隐式开启、显式提交)
总结:MYSQL 默认为每条sql开启事务,并且会在本条sql执行完毕后自动执行commit提交
若想设置手动提交,有两种方式
1, 直接用 SET 来改变 MySQL 的自动提交模式(下述设置均为会话级别的设置):
SET AUTOCOMMIT=0 禁止自动提交
SET AUTOCOMMIT=1 开启自动提交
2, 手动开启的事务里默认不会自动提交
需要手动commit或者回滚操作 backroll
4,如何开启事务(默认开启)
1,mysql默认开启事务
mysql> select * from excel;
+----+---------+--------+--------+--------+
| id | name | gender | office | salary |
+----+---------+--------+--------+--------+
| 1 | tom | f | a1 | 12000 |
| 2 | lily | m | b2 | 8000 |
| 3 | alex | f | c3 | 6700 |
| 4 | xiaohua | m | a1 | 9700 |
+----+---------+--------+--------+--------+
mysql> update excel set name='ttom' where id=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from excel;
+----+---------+--------+--------+--------+
| id | name | gender | office | salary |
+----+---------+--------+--------+--------+
| 1 | ttom | f | a1 | 12000 |
| 2 | lily | m | b2 | 8000 |
| 3 | alex | f | c3 | 6700 |
| 4 | xiaohua | m | a1 | 9700 |
+----+---------+--------+--------+--------+
2,开启事务
开启事务 start transaction;或者begin;
提交事务 commit;
回滚事务 rollback
commit或者rollback事务都结束
mysql> select * from excel;
+----+---------+--------+--------+--------+
| id | name | gender | office | salary |
+----+---------+--------+--------+--------+
| 1 | ttom | f | a1 | 12000 |
| 2 | lily | m | b2 | 8000 |
| 3 | alex | f | c3 | 6700 |
| 4 | xiaohua | m | a1 | 9700 |
+----+---------+--------+--------+--------+
mysql> update excel set name='ttttom' where id=1;
mysql> select * from excel;
+----+---------+--------+--------+--------+
| id | name | gender | office | salary |
+----+---------+--------+--------+--------+
| 1 | ttttom | f | a1 | 12000 |
| 2 | lily | m | b2 | 8000 |
| 3 | alex | f | c3 | 6700 |
| 4 | xiaohua | m | a1 | 9700 |
+----+---------+--------+--------+--------+
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from excel;
+----+---------+--------+--------+--------+
| id | name | gender | office | salary |
+----+---------+--------+--------+--------+
| 1 | ttom | f | a1 | 12000 |
| 2 | lily | m | b2 | 8000 |
| 3 | alex | f | c3 | 6700 |
| 4 | xiaohua | m | a1 | 9700 |
+----+---------+--------+--------+--------+
以上在rollback后,事务已经结束,查询表并没有更新
如下,commit提交后,查询表已经提交更新
mysql> update excel set name='ttttom' where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from excel;
+----+---------+--------+--------+--------+
| id | name | gender | office | salary |
+----+---------+--------+--------+--------+
| 1 | ttttom | f | a1 | 12000 |
| 2 | lily | m | b2 | 8000 |
| 3 | alex | f | c3 | 6700 |
| 4 | xiaohua | m | a1 | 9700 |
+----+---------+--------+--------+--------+
二,数据库读现象
1,脏读
# 事务终端2 修改了一条数据,这时事务终端1读取更新后的行;终端2做了回滚操作,取消刚刚的修改;这时终端一读取的行便无效了,称之为脏读
2,不可重复读
# 事务终端1读取了行记录,事务终端2对刚刚事务终端1读取的行做了修改并提交;终端1再次读取了行记录发现结果不一样,称之为不可重复读
3,幻像读(不可重复读的特殊场景)
# 事务终端1查询了where的一条记录,事务终端2插入了一行记录,正好满足终端1的查询语句;这时终端1再次检索刚刚的语句,发现多出了一条记录,称之为幻像读
三,锁机制
锁的分类
按照锁的颗粒划分:行级锁,表级锁,页级锁
按照锁的级别划分:共享锁,排他锁
按照使用的方式划分:乐观锁,悲观锁
1,行级锁—排它锁(X锁)
行级锁:
概念:行级锁只针对当前操作的行进行加锁。
用处:行级锁能大大减少数据库操作的冲突。
种类:行级锁分为共享锁 和 排他锁。
insert delete update ----->默认排它锁
select默认不加锁,如果加锁
select... from... for update;排它锁
select... from... lock in share mode;共享锁
注意⚠️
排它锁:
事务1一旦对数据A加了排它锁,其他事务无法对数据A加任何锁;只有事务1可以操作数据A,可读可写
示例一:
开启两个终端
终端1:
mysql> select * from excel;
+----+---------+--------+--------+--------+
| id | name | gender | office | salary |
+----+---------+--------+--------+--------+
| 1 | ttttom | f | a1 | 12000 |
| 2 | lily | m | b2 | 8000 |
| 3 | alex | f | c3 | 6700 |
| 4 | xiaohua | m | a1 | 9700 |
+----+---------+--------+--------+--------+
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update excel set name='abc' where id=3;
Query OK, 1 row affected (0.01 sec)
#并没有执行commit或者rollback
终端2:
mysql> update excel set name='cccc' where id=3;
#会一直停在原地,执行不了,直接锁定
PS:以上,一旦终端1执行commit或者rollback,会释放锁,终端2便可以执行
示例二: select
终端1:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from excel where name=4 for update;
Empty set, 4 warnings (0.00 sec)
# for update排它锁
终端2:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from excel where id > 2 for update;
或
mysql> update excel set name='huaer' where id=3;
#也会停在原地,执行不了
PS:
一旦终端一 commit或者rollback,终端2就可以执行;
注意:如果表没有设置索引,执行以上操作会锁表!!!(没有命中索引)
2,行级锁—共享锁(S锁)
注意⚠️
共享锁:又称连锁,多个事务对于同一数据可以共享一把锁,只读数据,释放所有的共享锁才能修改
示例:
事务1:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from excel where name=4 lock in share mode;
Empty set, 4 warnings (0.00 sec)
事务2:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from excel where name=4 for update;
#在事务1加了共享锁的基础上,事务2对同行记录做排它锁执行不成功
mysql> select * from excel where name=4 lock in share mode;
Empty set, 4 warnings (0.00 sec)
# 也加上共享锁成功
PS:
在以上事务1和事务2都加了共享锁的情况下,都执行以下
会出现“死锁”
事务1:
mysql> update excel set name='777' where id=1;
#会停在原地,执行不成功
事务2:
mysql> update excel set name='777' where id=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
这时再查看事务1:
mysql> update excel set name='777' where id=1;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
#会提示死锁,默认强制退出事务
大多数死锁问题,innodb存储引擎都会发现并抛出异常,但是有一种死锁非常隐蔽;
innodb存储引擎锁的是索引,如果命中的是辅助索引,则会锁住辅助索引的记录,再锁住对应的聚集索引的记录
3,乐观锁悲观锁
悲观锁:担心别人会加锁,干错自己就直接加一把排他锁;
乐观锁:原理是不加锁的,比如,在生产环境中,先查询当前的版本号(类似对当前快照记录)对数据增删改之后,再次查看当前的排版号,如果不一样,则操作失败
4,innodb支持锁特点
1,如果命中了主键索引,则直接锁住主键所对应的一条记录
2,如果命中的辅助索引,会先锁住该非辅助索引,再锁定相关的主键索引
3,如果没有设置索引,则会锁住表
PS:
1,拿到共享锁,只能看不能改(在别人已经为数据加了共享锁的前提下);如果只有自己设置了共享锁,自己也可以改也可以查
2,自己设置了排他锁,可以改也可以查
innodb存储引擎行锁的三种算法:
Record Lock行锁
Gap Lock 间隙锁
Next-Key Lock(默认) = Record Lock + Gap Lock
注:
id num
1 2
2 4
4 5
4 6
id为聚簇索引,num为辅助索引
间隙锁,比如select 一条数据条件是num = 4 for updates;
那么插入一条数据为 3 5;其中num5 是在4的上下范围中;则会阻塞在原地
PS:
在RR机制下,才会有锁间隙,而RR机制是mysql的 默认事务隔离机制,所以在默认情况下,innodb其实是锁行以及锁间隙
RR(Repeatable reads),可重复度,一种隔离事务机制;解决了脏读和可重复读的事务现象;但是幻读现象依然存在;而以上的默认行算法正好解决了幻读
网友评论