6.1 什么是事务
要么都成功,要么都失败
举例:转账
假设有两条sql都在执行
SQL1: A给B转账
SQL2: B收到A的钱
假设A给B转账的时候服务器崩了,B收到了,钱就没了,B没收到,钱也没了
A最开始有1000,B最开始有 200
B收到之后应该是A剩800,B剩400
这两个SQL同时执行完,这个事件才算结束
如果A给B转了B没收到,钱不见了,这肯定是不行的,事务就是解决这个问题,两个SQL,必须要么都成功,要么都失败
核心:将一组SQL放在一个批次中去执行
在最新的版本里面,MyIsam也是支持事务的
事务原则(ACID):原子性、一致性、持久性、隔离性,可能会出现脏读,幻读。。
一、原子性(atomicity)
一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作,这就是事务的原子性
二、一致性(consistency)
比如转账之前A和B一共有1200,转账之后A和B的钱也应该是1200,即事务前后的数据完整性要保持一致
事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态。
如果数据库系统在运行过程中发生故障,有些事务尚未完成就被迫中断,这些未完成的事务对数据库所作的修改有一部分已写入物理数据库,这是数据库就处于一种不正确的状态,也就是不一致的状态
三、隔离性(isolation)
互不干扰
事务的隔离性是指在并发环境中,并发的事务时相互隔离的,一个事务的执行不能不被其他事务干扰。不同的事务并发操作相同的数据时,每个事务都有各自完成的数据空间,即一个事务内部的操作及使用的数据对其他并发事务时隔离的,并发执行的各个事务之间不能相互干扰。
假设A给B转钱的时候,C也在给B转钱,它们之间不会互相影响,它们之间是隔离的,保证数据不会出现问题
隔离失败,就会出现问题,比如脏读,幻读
脏读:一个事务读取了另外一个事务未提交的数据
不可重复读:多次读取的结果不一致,可能A刚读完的数据,被B修改了
虚读(幻读):是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。/一个未提交事务读取到另一提交事务添加数据
四、持久性(durability)
事务一单提交,就不可逆转
一旦事务提交,那么它对数据库中的对应数据的状态的变更就会永久保存到数据库中。–即使发生系统崩溃或机器宕机等故障,只要数据库能够重新启动,那么一定能够将其恢复到事务成功结束的状态,不随着外界原因导致数据丢失
事务没有提交:就恢复到原状
事务已经提交,就持久化到数据库
就是假设出现了意外,只要没提交,就恢复到原来的状态,一旦提交,就持久化到数据库
一个事务的执行流程
-- ==========事务===
-- mysql默认开启事务自动提交
set autocommit=0 -- 关闭 因为事务是默认开启的,所以我们要手动开启一个事务就先关闭自动提交 set autocommit=0
-- set autocommit=1 -- 开启(默认的)-- 执行一句话就会默认提交一个事务
-- 手动处理事务
-- 事务开启
start transaction -- 标记一个事务的开始,这句话之后的sql,都在同一个事务内
-- 提交:持久化(如果成功,就提交)
commit
-- 回滚:回到原来的样子(如果失败,就回滚)
rollback
-- 事务结束
set autocommit=1 -- 确定事务提交完成,把自动提交事务开启,相当于恢复mysql的默认设置
-- 了解
savepoint 保存点名 -- 设置一个事务的保存点
rollback to savepoint 保存点名 -- 回滚到保存点
release savepoint 保存点名 -- 撤销保存点
测试事务实现转账
-- 创建数据库
create database bank character set utf8 collate utf8_general_ci
use bank
create table `account`(
`id` int(3) not null auto_increment,
`name` varchar(30) not null,
`money` decimal(9,2) not null,
primary key(`id`)
)engine=innodb default charset=utf8 -- INNODB才能支持事务
insert into `account`(`name`,`money`) values ('A',2000.00),('B',10000.00)
-- 转账是一个事务的操作
SET autocommit=0; -- 关闭自动提交
START TRANSACTION -- 开启一个事务(一组事务)
UPDATE `account` SET `money`=`money`-500 WHERE `nmae`='A' -- A减500
UPDATE `account` SET `money`=`money`+500 WHERE `name`='B' -- B加500
COMMIT; -- 执行成功就提交事务
ROLLBACK; -- 执行失败就回滚
SET autocommit=1; -- 恢复默认值(恢复自动提交)
如果提交之前执行ROLLBACK,事务就会回滚; – 执行失败就回滚
如果执行了 COMMIT; – 执行成功就提交事务,那么就不能回滚
参考:
事务ACID理解