事务
概念
构成单一逻辑工作单元的操作集合,我们称为事务(transaction)。要么全部执行,要么由于故障全部不发生。
事务的基本操作
START TRANSACTION/BEGIN:开启一个事务,标记事务的起点
COMMIT:提交事务,表示事务成功被执行
ROLL BACK
SAVEPOINT
RELEASE SAVEPOINT:
create database tx_db;
use tx_db;
create table t_account(
id int primary key auto_increment,
name varchar(255) not null,
balance decimal(12, 2)
);
insert into t_account values(null, 'Thomas_He', 1000);
insert into t_account values(null, '刘亦菲', 100000000);
update t_account set balance = balance - 100 where id = 1;
update t_account set balance = balance + 100 where id = 2;
select * from t_account;
# start transaction;
# begin;
# select @@autocommit; 查看autocommit参数 = 1 时,把每条sql语句看成一个事务
set autocommit = 0; # 不再自动提交,相当于开启事务 或者 start transaction
update t_account set balance = balance - 100 where id = 1; # 还没commit的情况下,不会自动提交。称为一个原子操作
update t_account set balance = balance + 100 where id = 2;
commit;
# savepoint sp; -- 设置回滚点
# rollback ; -- 回滚到事务开启前的状态。不表示发生故障,而是一个数据库操作。
# rollback to sp; -- 回滚到某个回滚点的状态
# release savepoint sp; -- 删除回滚点
set autocommit = 0; # 相当于开启事务
update t_account set balance = balance - 100 where id = 1;
savepoint sp1;
update t_account set balance = balance + 100 where id = 2;
rollback to sp1;
commit;
set autocommit = 0; # 相当于开启事务
insert into t_account values(null, '小龙女', 0);
insert into t_account values(null, null, 0);
commit;
select * from t_account;
事务的性质 ACID
原子性(Atomicity)
一致性(Consistency):满足相同的约束
隔离性(Isolation)
持久性(Durability)
并发执行可能会引发的问题和MySQL的隔离级别
#################################### 隔离级别 ############################################
-- 脏写 脏读 不可重复读 幻读
-- read uncommitted × √ √ √
-- read committed × × √ √
-- repeatable read × × × √
-- serializable × × × ×
# 查看隔离级别
select @@session.tx_isolation; # REPEATABLE-READ 查询本次会话的隔离级别
select @@global.tx_isolation; # REPEATABLE-READ, 查询的是会话的默认隔离级别
# 设置隔离级别
set global transaction isolation level read uncommitted;
select @@session.tx_isolation; # REPEATABLE-READ 下次才生效
select @@global.tx_isolation; # READ-UNCOMMITTED
# 代码演示
# 1. 读未提交
set session transaction isolation level read uncommitted;
# 1.1 脏写(×)
set @@autocommit = 0;
update t_account set balance = balance + 100 where id = 1; # 在提交前,如果有其他的写操作,则其他写操作会被卡住。等待该事务commit。
commit;
# 1.2 脏读 (√)
set @@autocommit = 0;
select * from t_account where id = 1; # 另一个事务改变了此表的数据,但是未提交,在此就读到了另一个事务未提交的表的数据,证明其存在脏读。
-- 提交后
# 1.3 不可重复读 (√)
select * from t_account where id = 1; # 另一个事务提交了它更新的数据,在此读到了另一个事务所提交的数据,证明其存在不可重复读。
commit;
# 1.4 幻读 (√)
set @@autocommit = 0;
select * from t_account;
-- 提交后
select * from t_account;
commit;
# 2. 读已提交
set session transaction isolation level read committed;
# 2.1 脏读 (×)
set @@autocommit = 0;
select * from t_account where id = 1;
-- 提交后
# 2.2 不可重复读 (√)
select * from t_account where id = 1;
commit;
# 2.3 幻读 (√)
set @@autocommit = 0;
select * from t_account;
-- 提交后
select * from t_account;
commit;
# 3. 可重复读
set session transaction isolation level repeatable read;
# 3.1 脏读 (×)
set @@autocommit = 0;
select * from t_account where id = 1;
-- 提交后
# 3.2 不可重复读 (×)
select * from t_account where id = 1;
commit;
# 3.3 幻读 (√)
set @@autocommit = 0;
select * from t_account;
-- 提交后
select * from t_account;
commit;
# 注意事项:MySQL对可重复读隔离级别的实现比较特殊, 它能杜绝大多数幻读现象出现。
# 但是SQL标准,不要求RR隔离界别避免幻读现象。
# 4. 可串行化