准备工作:导入company数据库
1、事务概述
指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源
2、Mysql事务控制语句
START TRANSACTION | BEGIN [WORK]
COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
(1) 查看MySQL隔离级别
> show variables like 'tx_isolation';
(2) 创建测试表,存储引擎为InnoDB
> create database test;
> use test;
> create table test_1(id int, username varchar(20)) engine=InnoDB;
> insert into test_1 values(1,'petter'),(2,'bob'),(3,'allen'),(4,'aron');
> select * from test_1;
(3) 开启一个事务
> begin;
(4) 更新一条记录
> update test_1 set username='test' where id=1;
此时打开另外一个窗口输入
> select * from test_1;
(5) 提交事务
> commit;
此时打开另外一个窗口输入
> select * from test_1;
发现记录以及生效
> select * from test_1;
(6) 开启另外一个事务
> begin;
> update test_1 set username='petter' where id=1;
> select * from test_1;
(7) 事务回滚
> rollback;
此时打开另外一个窗口输入
> select * from test_1;
发现此时数据已经回滚
> rollback;
SET AUTOCOMMIT = {0 | 1}
> set autocommit=0; #不自动提交
> insert into test_1 values(5,'snow');
> rollback; #事务被撤销
> select * from test_1;
> set autocommit=1; #自动提交
> insert into test_1 values(5,'snow');
> rollback;#事务撤销无用
> select * from test_1;
3、Mysql事务隔离级别
未提交读
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
提交读
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
可重复读
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
可串行化
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
3.1 read-uncommitted (读取未提交内容)
查看MySQL隔离级别。
> show variables like 'tx_isolation'; #显示默认隔离级别REPEATABLE-READ
所有事务都可以看到其他未提交事务的执行结果,读取未提交的数据被称为脏读(Dirty Read)
脏读演示:
前期准备:
首先更改隔离级别
>SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
>show variables like ‘%tx%’;#显示不变,需要重新登录才有效。
建立数据库testdb,再建立表users
> create database testdb;
> use testdb;
> create table users(id integer);
> insert into users values(1),(2),(3),(4);
开两个窗口,同时打开表users的数据,确实一致,并确认隔离级别
下面开始脏读演示
两个窗口同时操作
>begin;
>select * from users;
对B事务(右窗口)执行
>update users set id=123 where id=1;
对B事务执行
>select * from users;
对A事务(左窗口)执行
>select * from users;(B事务虽然没有提交,但A事务中已经可以看到结果)
对B事务进行回滚, 并查看数据
>rollback;
>select * from users;
在A事务中使用
>select * from users;发现前后数据不一致,就为脏读问题。
3.2 read-committed (读取未提交内容)
事务只能看见已经提交事务所做的改变,同一查询可能返回不同结果,此级别导致的不可重复读问题。
Read-committed级别不可重复读问题演示。
首先更改隔离级别
>SET GLOBAL TRANSACTION ISOLATION LEVEL read-committed;
>show variables like ‘%tx%’;#显示不变,需要重新登录才有效。
开两个窗口,同时打开表users的数据,确实一致,并确认隔离级别
两个窗口同时操作
>begin;
>select * from users;
对B事务(右窗口)执行
>update users set id=2 where id=123;
对B事务执行
>select * from users;
对A事务(左窗口)执行
>select * from users;
对B事务进行提交
>commit;
>select * from users;
对A事务进行查看
>select * from users; 因为A事务没有完成,不管B事务做什么处理,A事务的数据都不变。
3.3 repeatable-read (可重读)
能确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。(不管别人有没有提交)
repeatable-read级别可重读问题演示。
首先更改隔离级别
>SET GLOBAL TRANSACTION ISOLATION LEVEL repeatable-read;
>show variables like ‘%tx%’;#显示不变,需要重新登录才有效。
开两个窗口,同时打开表users的数据,确实一致,并确认隔离级别
两个窗口同时操作
>begin;
>select * from users;
对B事务(右窗口)执行
>update users set id=123 where id=2;
对B事务执行
>select * from users;
对A事务(左窗口)执行
>select * from users;
对B事务进行提交
>commit;
>select * from users;
对A事务进行查看
>select * from users; A事务前后数据不一致,造成了不可重复读问题
3.4 SERIALIZABLE (隐式事务提交)
这是最高的隔离级别,通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。即在每个读的数据行上加上共享锁实现。
在这个级别,可能会导致大陆的超时现象和锁竞争,一般不推荐。
SERIALIZABLE (隐式事务提交)级别问题演示。
首先更改隔离级别
>SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABL;
>show variables like ‘%tx%’;#显示不变,需要重新登录才有效。
开两个窗口,同时打开表users的数据,确实一致,并确认隔离级别
两个窗口同时操作
>begin;
>select * from users;
对B事务(右窗口)执行
>update users set id=1111 where id=1;
对B事务执行
>select * from users;
对A事务(左窗口)执行
>select * from users;
4、InnoDB锁机制
为解决数据库并发控制问题,如在同一时刻,客户端对于同一个表做更新或者查询操作,为保证数据的一致性,需要对并发操作进行控制,因此产生了锁。同时为实现MySQL的各个隔离基本,锁机制为其提供了保证。
首先更改隔离级别
>SET GLOBAL TRANSACTION ISOLATION LEVEL repeatable-read;
>use testdb;
>select * from users;
>show create table users; #可以查看里面没有主键,也没有索引
开启A事务,同时开启B事务
>begin;
首先在A事务中更新一条记录
>update users set id=1111 where id=1;
再在B事务中更新一条记录
>update users set id=111111 where id=1; #此时发现B事务被锁定了,可以尝试在另外的一个窗口再更新一个记录,也会被锁住,即所有的更改都将被锁住,这需要等待前一个记录将锁释放。
下面为表增加索引,对表首先进行回滚
>rollback; 多次
>alter table users add index index_id(id);
查看
>show create table users \G
下面再重复之前的过程,
>begin;
首先在A事务中更新一条记录
>update users set id=1111 where id=1;
可以发现可以在别的窗口对id不为1进行更新,id为1还是会被锁定。
但若对A事务进行rollback,B事务id为1的才能运行
对一个范围进行更改:
>begin;
>update users set id=1111 where id<10; 注意会锁定比10小的和比10大1的
比如在另外窗口更改id=11则会被锁住
查看存储引擎的锁的情况
>show engine innodb status \G
查看Transcations段
Comments