事务的概念
比如在一个人员管理系统中,你删除一个人员,就需要删除人员的基本资料、人员相关信息(信箱文档等等),这些数据库操作就构成一个事务。
事务是一个最小的不可再分的工作单元。
一个完整的业务需要批量的 DML(insert、update、delete)语句共同联合完成,事务只和 DML 语句有关,或者说 DML 语句才有事务。这个和业务逻辑有关,业务逻辑不同,DML 语句的个数不同。
所以,在 Mysql 中事务主要用来处理操作量大、复杂度高的数据。
- mysql中只有 Innodb 数据库引擎的数据库或表才支持事务;
- 事务处理可以用来维护数据库的完整性。要么全部执行,要么全部不执行;
- 事务是用来管理
update\ delete\ insert
的操作;
一般来说,事务必须满足4个条件:
- 原子性:一组事务,要么成功,要么撤回;
- 稳定性:有非法数据(外键约束之类),事务撤回;
- 隔离性:事务独立运行。一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。事务的100%隔离,需要牺牲速度;
- 可靠性:软、硬件崩溃后,InnoDB 数据表驱动会利用日志文件重构修改。可靠性和高速度不可兼得,innodb_flush_log_at_trx_commit 选项决定什么时候把事务保存到日志里。
事务的隔离级别:
- 读未提交:read uncommitted
- 读已提交:read committed
- 可重复读:repeatable read
- 串行化:serializable
:::info
读未提交:事务A和事务B,事务A未提交的数据,事务B可以读取到;这里读取到的数据叫“脏数据”,这种隔离级别最低,一般是理论上存在,数据库隔离级别一般都高于该级别;
读已提交:事务A和事务B,事务A提交的数据,事务B才能读取到;这种级别可以避免“脏数据”,但这种隔离级别会导致“不可重复读取”;
可重复读:事务A提交之后的数据,事务B读取不到,事务B可以重复读取数据,这种隔离级别高于读已提交;这种级别可以避免“不可重复读取”,达到可重复读取,但是会导致“幻象读”,mysql默认级别;
串行化:事务A和事务B,事务A在操作数据库时,事务B只能排队等待,这种隔离级别很少使用,吞吐量太低,用户体验差;这种级别可以避免“幻象读”,每一次读取都是数据中真实存在数据,事务A和事务B串行,而不并发。
:::
事务会用到 TCL (Transaction Controll Language)语句。
- commit:提交
- rollback:回滚
事务提交与回滚实现。
-- 事务提交,一次性提交所有修改
start transaction
DML语句
commit
-- 事务回滚,回滚所有修改
start transaction
DML语句
rollback
mysql中操作事务
通过 begin
开启事务后,执行的数据都只是暂时的插在内存里,还没刷到硬盘上;这时如果你发现有错,就可以通过 rollback
将这些操作撤回;如果没有问题就通过 commit
刷到硬盘中;
commit
之后再 rollback
就没作用了。
/*
* 事务回滚与提交
*/
-- 创建人员表
create table if not exists t_Account(
pid int primary key auto_increment,
pname varchar(20),
account decimal(5)
);
-- -- 初始化,张三500,李四100
insert into t_Account(pname, account) values("张三", 500);
insert into t_Account(pname, account) values("李四", 100);
-- 查询数据
select * from t_Account;
-- 实现转账: 张三转账100给李四,张三余额400,李四余额200
update t_Account set account = account - 100 where pid = 1;
update t_Account set account = account + 100 where pid = 2;
commit提交事务
为了测试,这里要开两个控制台测试。
-- 控制台A开启事务: 张三再次给李四转账100,张三余额300,李四余额300
start transaction;
update t_Account set account = account - 100 where pid = 1;
update t_Account set account = account + 100 where pid = 2;
-- commit提交事务
commit;
-- 控制台B分别查询查看数据变化
select * from t_Account;
rollback回滚事务
-- 控制台A开启事务: 张三继续给李四转账100,张三余额200,李四余额400
start transaction;
update t_Account set account = account - 100 where pid = 1;
update t_Account set account = account + 100 where pid = 2;
-- commit提交事务
rollback;
-- 控制台B分别查询查看数据变化
select * from t_Account;
【注意】如果事务已经 commit 之后,再 rollback 回滚,那么 rollback 无效。
to be continue…