准备工作:导入company数据库

1、事务概述

指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源

 

2Mysql事务控制语句

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;

 

 

3Mysql事务隔离级别

未提交读

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;

 

4InnoDB锁机制

为解决数据库并发控制问题,如在同一时刻,客户端对于同一个表做更新或者查询操作,为保证数据的一致性,需要对并发操作进行控制,因此产生了锁。同时为实现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进行更新,id1还是会被锁定。

但若对A事务进行rollbackB事务id1的才能运行

 

对一个范围进行更改:

>begin;

>update users set id=1111 where id<10; 注意会锁定比10小的和比101

 

比如在另外窗口更改id=11则会被锁住

 

查看存储引擎的锁的情况

>show engine innodb status \G

查看Transcations