CREATE TABLE `cs` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`num` int(10) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
自动提交(auto commit),指的是SQL语句执行完毕后自动将数据持久化到磁盘(刷盘)中。
显式的声明事务,或者声明set autocommit = 0;
都可以关闭自动提交。
start transaction;
insert into cs(num) values(1);
savepoint insert_1;
insert into cs(num) values(2);
savepoint insert_2;
insert into cs(num) values(3);
savepoint insert_3;
insert into cs(num) values(4);
savepoint insert_4;
rollback to insert_2;
commit;
发现1,2数据被插入。
在上一个事务没提交或回滚时,运行下一个事务,则上一个事务自动提交。
start transaction;
insert into cs(num) values(1);
insert into cs(num) values(2);
start transaction;
insert into cs(num) values(3);
insert into cs(num) values(4);
commit;
成功插入1,2,3,4。
表格从上到下,越来越高可用,但是性能越来越低。
隔离级别 | 是否解决脏读 | 是否解决不可重复读 | 是否解决幻读 | 是否加锁 |
---|---|---|---|---|
读未提交 | 否 | 否 | 否 | 否 |
读已提交 | 是 | 否 | 否 | 否 |
可重复读 | 是 | 是 | 否 | 否 |
串行化 | 是 | 是 | 是 | 是 |
select @@transaction_isolation;
或者 show variables like 'transaction_isolation;'
set session transaction_isolation = 'read-uncommitted/read-committed/repeatable-read/serializable'
;因为mysql默认隔离级别是可重复读(Repeatable Read),所以只会发生幻读情况,脏读和可重复度不会发生,除非改事务隔离级别。
步骤 | 会话A | 会话B | 备注 |
---|---|---|---|
1 | set session transaction_isolation = 'read-committed'; | set session transaction_isolation = 'read-committed'; | 设置事务的隔离级别为读未提交 |
2 | select @@transaction_isolation; | select @@transaction_isolation; | 检查隔离级别是否设置成功 |
3 | select num from cs where id = 20; #20 | start transaction; update cs set num = 20 where id = 40; |
会话A num的初始值为20 |
4 | select num from cs where id = 20; #40 | / | 会话B并未commit,此时会话A中num的值为40,发生脏读现象 |
5 | / | rollback | 结束本次事务 |
6 | select num from cs where id = 20; #20 | / | num恢复为20 |
步骤 | 会话A | 会话B | 备注 |
---|---|---|---|
1 | set session transaction_isolation = 'read-uncommitted'; | set session transaction_isolation = 'read-uncommitted'; | 设置事务隔离级别为读已经提交 |
2 | select @@transaction_isolation; | select @@transaction_isolation; | 检查隔离级别是否设置成功 |
3 | start transaction; | start transaction; | 双方开启事务 |
4 | select num from cs where id = 20; #20 | select num from cs where id = 20; #20 | 两个会话中num的值为20 |
5 | update cs set num = 40 where id = 20; | select num from cs where id = 20; #20 | 会话A将数据更新为40,此时会话B查询的值仍为20 |
6 | commit | select num from cs where id = 40; #40 | 会话A提交事务,会话B仍在事务中,但是得到的值变成了40,发生了不可重复读 |
7 | / | commit | 结束事务 |
步骤 | 会话A | 会话B | 备注 |
---|---|---|---|
1 | select @@transaction_isolation; | select @@transaction_isolation; | 检查隔离级别是否是REPEATABLE-READ |
2 | start transaction; | start transaction; | 双方开启事务 |
3 | select * from cs; | select * from cs; | 两个事务查看,都只有id为20的一条数据 |
4 | insert into cs (id,num) values(21,21); | select * from cs; | 会话B查询,仍旧只有id为20的一条数据 |
5 | commit | / | 会话A提交事务 |
6 | / | select * from cs; | 即使会话A提交了事务,会话B查询仍旧无法搜索到会话A插入的数据,起始这一步已经幻读了,但是mysql不表明是幻读,所以到第7步测试 |
7 | / | insert into cs (id,num) values(21,21); | 因为会话B select查不到id为21的数据,所以插入id相同的数据,但是报错1062 - Duplicate entry '21' for key 'PRIMARY' |
8 | / | rollback; | 回滚以结束事务流程 |
当前读读的就是数据最新的记录,需要保证当前读的数据不能被修改,修改了就不是最新的记录了(脏写),因此需要加锁,select for update、select lock in share mode以及DML(insert、update、delete)获取的数据都是当前读的数据。
快照读顾名思义,读取的就是由MVCC Read View控制的undo log的数据,不加锁,所以是读取是非阻塞的。不加锁的select都属于快照读。如果当前事务的隔离级别是串行化,那么快照读也变成了当前读。
举个例子:常用的navicat,查看一个表,事务提交前的insert或update语句,表格内仍旧显示的原数据,则用的快照读。
MVCC(Multi-Version Concurrency Control)是 MySQL 中一种实现事务隔离的机制,用于处理数据库事务并发访问时可能出现的读写冲突。事务的四种隔离级别,就是通过MVCC机制提供的底层支撑。
MVCC三板斧:隐藏字段、Undo log(存放历史版本)、Read view(版本控制)
MVCC解决的是读已提交和可重复读级别的并发控制。
因为读未提交,就算事务未提交,可以直接读取最新的数据(脏读),相当于当前读,那就不分快照读和当前读了。
串行化的隔离级别,强制事务串行执行,也不存在快照读和当前读的区分,因为读取的都是事务执行过后的最新数据。
查看 InnoDB 存储引擎中当前活动的事务信息。
SELECT * FROM information_schema.innodb_trx;
trx_id 事务的唯一标识符。
trx_state 事务的状态,如 RUNNING、LOCK WAIT、ROLLING BACK 等。
trx_started 事务启动的时间。
trx_requested_lock_id 请求的锁的标识符。
trx_wait_started 等待锁的开始时间。
trx_weight 事务的权重,用于死锁检测。
trx_mysql_thread_id MySQL 线程 ID。
trx_query 与事务相关的 SQL 查询语句。
trx_operation_state 事务内部操作的状态。
trx_tables_in_use 事务使用的表的数量。
trx_tables_locked 事务锁定的表的数量。
trx_lock_structs 事务内部使用的锁结构数量。
trx_lock_memory_bytes 用于事务锁定的内存字节数。
trx_rows_locked 事务锁定的行数。
trx_rows_modified 事务修改的行数。
trx_concurrency_tickets 用于事务并发控制的票数。
trx_isolation_level 事务的隔离级别。
trx_unique_checks 是否启用了唯一性检查。
trx_foreign_key_checks 是否启用了外键约束检查。
trx_last_foreign_key_error 最后一个外键错误信息。
trx_adaptive_hash_latched 是否适应性哈希被锁定。
trx_adaptive_hash_timeout 适应性哈希锁定超时次数。
trx_is_foreign_key_with_check 是否用于外键约束检查。
trx_is_foreign_key 是否用于外键约束。
参与评论
手机查看
返回顶部