[MySQL光速入门]020 事务

TCL 事务控制语言

SQL的四种语言

  1. DDL(Data Definition Language)数据库定义语言 建表, 建库, 修改表结构
  2. DML(Data Manipulation Language)数据操纵语言 增删改查, select, insert, update, delete
  3. DCL(Data Control Language)数据库控制语言 修改用户权限, 重置密码
  4. TCL(Transaction Control Language)事务控制语言 建立事务, 回滚

什么是事务

一组SQL语句组成的执行单元, 这一组SQL语句, 要么所有执行, 要么所有不执行.
复制代码

举例sql

  • 郭靖向黄蓉转帐(交工资)
  • 郭靖这个月发了5000, 银行卡余额5000
  • 黄蓉, 银行卡余额5000,000
  • update set 郭靖的银行卡余额 - 5000;
  • update set 黄蓉的银行卡余额 + 5000;
  • 咱们须要两条SQL语句都要成功, 不然咱们宁愿没执行过, 因此就是, 要么所有执行, 要么所有不执行.

事务:数据库

  • 事务由单独单元的一个或多个SQL语句组成
  • 在这个单元中,每一个MySQL语句是相互依赖的
  • 而整个单独单元做为一个不可分割的总体
  • 若是单元中某条SQL语句一旦执行失败或产生错误,整个单元将会回滚
  • 全部受到影响的数据将返回到事物开始之前的状态
  • 若是单元中的全部SQL语句均执行成功,则事物被顺利执行

举例2:session

  • 软件安装, 会有不少下一步, 若是点击取消, 则所有回滚.

image.png

事务 vs 存储引擎(表类型)

什么是存储引擎(表类型):

  • MySQL中的数据用各类不一样的技术存储在文件(或者内存)中。
  • 这些技术中的每一种技术都使用不一样的存储机制、索引技巧、锁定水平而且最终提供普遍的不一样的功能和能力。
  • 经过选择不一样的技术,你可以得到额外的速度或者功能,从而改善你的应用的总体功能。
  • 若是你在研究大量的临时数据,你也许须要使用内存MySQL存储引擎(memory)。
  • 内存存储引擎可以在内存中存储全部的表格数据。
  • 又或者,你须要一个支持事务处理的数据库(以确保事务处理不成功时数据的回退能力), 那就用innodb
  • 这些不一样的技术以及配套的相关功能在 MySQL中被称做存储引擎(也称做表类型)。

为何须要多个存储引擎?

  • 每种引擎都有各自的优点和不足, 没有一种完美的存储引擎
  • 因此MySQL能够针对不一样的表, 选择不一样的存储引擎
  • 就像雷达图

image.png

image.png

image.png

如何设置表的存储引擎?

create table tb (id int) engine = myisam;
-- 或者
alter table tb engine = memory;
复制代码

查看全部存储引擎

show engines;
复制代码

image.png

innodb:
  • 支持事务, 查询速度没有myisam快, 容量没有myisam大
myisam:
  • 速度快, 容量大, 不支持事务
memory:
  • 速度超快, 容量取决于内存, 因此比较小, 不支持事务

事务的属性(ACID)

  • 原子性 atomicity并发

    • 事务是一个总体, 不可分割, (由于原子不可再分)
    • 要么所有执行, 要么所有不执行
  • 一致性 consistencyoop

    • 参见能量守恒定律
    • 能量既不会凭空产生,也不会凭空消失,只能从一个物体传递给另外一个物体,从一种形式变成另外一种形式, 在变换过程当中, 系统的总能量保持不变。
    • 事务必须是数据库从一个一致性状态到另外一个一致性状态
    • 好比转帐(事务)先后, 郭靖, 黄蓉的银行卡余额之和是固定不变的.
  • 隔离性(isolation)post

    • 一个事务的执行, 不受其余事务的干扰
    • 郭靖向黄蓉转帐的时候, 黄药师也能够向黄蓉转帐(须要配置隔离级别)
  • 持久性(durability)性能

    • 事务一旦成功, 不可撤销
    • 删除就是一个事务, 删库只能跑路
    • 转帐成功, 不能撤销, 除非对方再转给你, 这是另外一个事务

事务一般包括多条SQL语句(DML), 其实单独的DML语句, 也是一个事务测试

  • 隐式事务(自动提交)ui

    • 事务没有明显的开启和结束标记
    • 好比 insert,update,delete
  • 显式事务atom

    • 数据具备明显的开始和结束标记
    • 前提, 必须设置自动提交功能为禁用 set autocommit = 0;
    • 不然每条语句都是一个事务

建立事务

查看变量

show variables like 'autocommit';
-- 或者
select @@autocommit;
复制代码

关闭自动提交

-- 当前会话有效
set autocommit = 0; 
-- 或者
set session autocommit = 0; 
-- 或者
set @@autocommit = 0;
-- 或者
set @@session.autocommit = 0;
复制代码

事务的建立

  1. 开启事务

    set autocommit = 0;
    start transaction; // 可选
    复制代码
  2. 编写事务中的sql语句(select, insert, update, delete) 不包括DDL(create, drop, alter)

  3. 结束事务

    • 提交事务 commit
    • 回滚事务 rollback

事务实操

drop table if exists test_tb;

CREATE TABLE `test_tb` (
  `id` int(5) unsigned NOT NULL,
  `age` tinyint(5) unsigned NOT NULL,
  `account` int(11) unsigned NOT NULL,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=innodb DEFAULT CHARSET=utf8;

INSERT INTO `test_tb`(`id`, `age`, `account`, `name`) VALUES (1, 11, 5000, '张三');
INSERT INTO `test_tb`(`id`, `age`, `account`, `name`) VALUES (2, 12, 5000, '李四');
复制代码

事务正常提交

set autocommit = 0;
start TRANSACTION;
update test_tb set account = account - 4000 where name = '张三';
update test_tb set account = account + 4000 where name = '李四';
commit;
复制代码

事务回滚

set autocommit = 0;
start TRANSACTION;
update test_tb set account = account - 4000 where name = '张三';
update test_tb set account = account + 4000 where name = '李四';
rollback;
复制代码

同时运行多个事务的时候...

对于同时运行的多个事务, 若是没有采用必要的隔离机制, 就会致使各类并发问题

事务冲突.png

脏读

  • 对于两个事务T1,T2, T1读取了已经被T2更新可是尚未被提交的字段以后
  • 若是T2回滚, T1读取的内容就是临时而且无效的
  • 好比, 有一天, 你查询余额, 发现多了100万!
  • 你难以压抑本身激动的心情, 给亲朋好友挨个打电话, 约他们吃饭
  • 等打完电话, 再看余额, 发现100万又没有了...
  • 原来是银行把钱打错了, 刚刚撤销了以前的转帐...

幻读

  • 对于两个事务T1,T2, T1从一个表中读取了一些数据
  • 而后T2在该表中插入/删除了一些新的行以后, 若是T1再次读取同一个表, 就会多出/少了几行.
  • 仿佛出现了幻觉
  • 好比, 你看见屋里只有两我的, 干干巴巴, 麻麻赖赖, 一点都不圆润
  • 知道吃得少, 因此你想耍一下大方
  • 就说"我今天请全部人吃饭!"
  • 刚说完, 又从外面进来两个, 他们问你:"你说请全部人吃饭? 好的! 好的!"
  • 你不敢相信本身的眼睛, 仿佛出现了幻觉...

image.png

不可重复读

  • 对于两个事务T1,T2, T1读取了一个字段,
  • 而后T2更新了该字段并提交, T1再次读取同一个字段, 值就不一样了.
  • 好比上午你去淘宝买东西, 一个手机1999, 果断下单
  • 到下午再看的时候, 手机已经发货, 可是售价变成了1799
  • 发生悲剧的缘由是, 上午卖家修改了价格, 可是没有提交, 下午已经提交了
  • 因此上午和下午, 你看到的价格不同...

数据库事务的隔离性:

  • 数据库系统必须具备隔离并发运行各个事务的能力, 使他们不会互相影响, 避免各类并发问题.
  • 一个事务与其余事务隔离的程度称为隔离级别
  • 数据库规定了多种事务隔离级别, 不一样隔离级别对应不一样的干扰程度
  • 隔离级别越高, 数据一致性越好, 但并发性越弱
  • 就像一次只作一件事, 没有其余事情的干扰, 确定不容易出错, 可是效率也会比较低

4种隔离级别

  1. 读未提交数据(read uncommitted)
    • 容许事务读取未被其余事务提交的变动
    • 脏读, 不可重复读幻读, 都会出现
  2. 读已提交数据(read commited)
    • 只容许事务读取已经被其余事务提交的变动, 能够避免脏读
    • 不可重复读幻读问题仍然可能出现
  3. 可重复读(repeatable read)
    • 确保事务能够从一个字段中读取相同的值, 在这个事务持续期间, 禁止其余事务对这个字段进行更新
    • 能够避免脏读不可重复读, 可是幻读问题让然存在
  4. 串行化(serializable)
    • 确保事务能够从一个表中读取相同的行
    • 在这个事务持续期间, 禁止其余事务对该表执行插入, 更新和删除操做, 全部并发问题均可以免
    • 可是性能十分低下

image.png

MySQL支持以上所有四种事务隔离级别, 默认 repeatable read(可重复读)

查看当前隔离级别

select @@tx_isolation;
-- 或者
show variables like "tx_isolation";
复制代码

设置隔离级别

set session transaction isolation level repeatable read; // 当前会话
-- 或者
set global transaction isolation level repeatable read; // 全局
复制代码

隔离级别验证

感兴趣的小伙伴们, 能够测试一下各个隔离级别的不一样 下面是测试须要时, 用到的数据

DROP TABLE IF EXISTS test;
CREATE TABLE test (
	id INT auto_increment PRIMARY KEY,
	NAME VARCHAR ( 10 ) NOT NULL,
	account INT ( 11 ) NOT NULL,
	age TINYINT ( 1 ) NOT NULL,
	sex CHAR ( 1 ) NOT NULL DEFAULT '男' 
);
INSERT INTO test ( NAME, account, age )
VALUES
	( '张三', 3000, 18 ),
	( '李四', 4000, 28 ),
	( '王五', 5000, 38 ),
	( '赵六', 6000, 48 ),
	( '孙七', 2000, 19 ),
	( '周八', 1000, 29 ),
	( '吴老九', 9000, 39 ),
	( '冯老十', 8000, 49 );
复制代码

冲突的级别

脏读、不可重复读、幻读的级别高低是:

脏读 < 不可重复读 < 幻读

因此,设置了最高级别的serializable就不用在设置repeatable readread committed

回滚点(savepoint)

就像玩游戏时的存盘点, 若是游戏人物死了, 就会在存盘点复活

直接上例子, 以上面的数据为例

set autocommit = 0;
start TRANSACTION;
update test set account = 9999 where id = 1;
SAVEPOINT a;
update test set account = 9999 where id = 2;
rollback to a;

select * from test;
复制代码

image.png

快速跳转

相关文章
相关标签/搜索