赞
踩
Innodb
引擎支持事务功能。更追求隔离性(数据更正确) | ----------------------------- | ------------------------------------------------ | ---------------------------------> | 更追求并发性(性能更高) |
---|---|---|---|---|
(可串行性)serializable | (快照读)snapshot_read | (可重复读)repeatable_read | (读已提交)read_committed | (读未提交)read_uncommitted |
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。 | 不是标准中存在的隔离级别,目前来说,没有副作用。 MySQL中的可重复读就是实际上的快照读。因为MVCC机制解决了幻读。 | 这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。这会导致幻读:当用户修改某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有一条未修改的数据“幻影” 。 | 只能读取其它事务已经提交的内容,存在不可重复读问题:一个事务多次读取同一数据可能会得到多个不同的结果 。 | 能够读取到其它事务中未提交的内容,存在脏读问题。读取未提交的数据,也被称之为脏读 。 |
我们可以修改隔离级别:
set session transaction isolation level read uncommitted;
①SQL开启事务
-- 开启事务
start transaction; / begin;
SQL1;
SQL2;
rollback; -- 主动回滚
-- 开启事务
start transaction; / begin;
SQL1;
SQL2;
SQL3;
commit; -- 提交事务,失败也会回滚
②JDBC使用事务
// 要使用事务,在同一个事务中,操作 sql1 和 sql2,意味着必须在一条 Connection 完成 try (Connection c = DBUtil.connection()) { // connection 中有一个自动提交(autocommit)的属性,默认情况下是 true(开启) // 开启状态下,意味着,每一条 sql 都会被独立的视为一个事务 // 我们要让 sql1 和 sql2 看作整体,只需要关闭 connection 的自动提交 c.setAutoCommit(false); // 此时就可以手动的控制事务的结束位置,并且需要手动提交 try (PreparedStatement ps = c.prepareStatement(sql1)) { ps.executeUpdate(); } try (PreparedStatement ps = c.prepareStatement(sql2)) { ps.executeUpdate(); } // 由于我们关闭了自动提交了,所以,所有的修改还没有真正地落盘 c.commit(); // 只有加上这句话,才表示事务被提交了(数据真正落盘了) }
我们知道在可重复读的级别下,MySQL 在一定程度上解决了幻读问题:
从对数据的操作类型上来说,锁分为读锁和写锁:
从锁的作用范围上划分,分为全局锁、表锁和行锁:
①全局锁:锁作用于全局,整个数据库的所有操作全部受到锁限制。
flush tables with read lock;
②表锁:锁作用于整个表,所有对表的操作都会收到锁限制。
lock table 表名称 read; -- 读锁
lock table 表名称 write; -- 写锁
-- 除了手动释放锁之外,当我们的会话结束后,锁也会被自动释放。
unlock tables;
③行锁:锁作用于表中的某一行,只会通过锁限制对某一行的操作(仅InnoDB支持)
-- 添加读锁(共享锁)
select * from 表名 where ... lock in share mode;
-- 添加写锁(排他锁)
select * from 表名 where ... for update;
我们知道 InnoDB 支持使用行锁,但是行锁比较复杂,它可以继续分为多个类型,详细可查看文章:MySQL的锁机制 - 记录锁、间隙锁、临键锁
①记录锁(Record Locks): 仅仅锁住索引记录的一行,在单条索引记录上加锁。Record lock 锁住的永远是索引,而非记录本身。所以说当一条 sql 没有走任何索引时,那么将会在每一条聚合索引后面加写锁,这个类似于表锁,但原理上和表锁应该是完全不同的。
②间隙锁(Gap Locks): 仅仅锁住一个索引区间(开区间)。在索引记录之间的间隙中加锁,或者是在某一条索引记录之前或者之后加锁,并不包括该索引记录本身。比如在 1、2 中,间隙锁的可能值有 (-∞, 1),(1, 2),(2, +∞),间隙锁可用于防止幻读,保证索引间的不会被插入数据。
③临键锁(Next-Key Locks): Record lock + Gap lock
,左开右闭区间。默认情况下,InnoDB 正是使用 Next-key Locks 来锁定记录(如select … for update
)。
它还会根据场景进行灵活变换:
场景 | 转换 |
---|---|
使用唯一索引进行精确匹配,但表中不存在记录 | 自动转换为 Gap Locks |
使用唯一索引进行精确匹配,且表中存在记录 | 自动转换为 Record Locks |
使用非唯一索引进行精确匹配 | 不转换 |
使用唯一索引进行范围匹配 | 不转换,但是只锁上界,不锁下界 |
总结:
提示:这里对文章进行总结:
本文是MySQL的学习,先学习了事务的四大特征、隔离级别,如何开启事务。又学习了锁机制,认识了读写锁、行表锁、记录锁等。之后的学习内容将持续更新!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。