总结
一般像这样的大企业都有好几轮面试,所以自己一定要花点时间去收集整理一下公司的背景,公司的企业文化,俗话说「知己知彼百战不殆」,不要盲目的去面试,还有很多人关心怎么去跟HR谈薪资。
这边给大家一个建议,如果你的理想薪资是30K,你完全可以跟HR谈33~35K,而不是一下子就把自己的底牌暴露了出来,不过肯定不能说的这么直接,比如原来你的公司是25K,你可以跟HR讲原来的薪资是多少,你们这边能给到我的是多少?你说我这边希望可以有一个20%涨薪。
最后再说几句关于招聘平台的,总之,简历投递给公司之前,请确认下这家公司到底咋样,先去百度了解下,别被坑了,每个平台都有一些居心不良的广告党等着你上钩,千万别上当!!!
Java架构学习资料,学习技术内容包含有:Spring,Dubbo,MyBatis, RPC, 源码分析,高并发、高性能、分布式,性能优化,微服务 高级架构开发等等。
还有Java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板可以领取+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书。
========================================================================
| MySQL系列文章 | 飞机票 |
| — | — |
| MySQL索引为何选择B+树 | 登机入口 |
| 深入分析MySQL索引 | 登机入口 |
| MySQL执行计划EXPLAIN详细说明和举例 | 登机入口 |
| MySQL中事务以及MVCC的实现原理 | 登机入口 |
| 深入分析MySQL中锁并详解幻读问题 | 登机入口 |
| select语句和update语句的执行流程 | 登机入口 |
| InnoDB引擎存储结构及Change Buffer和Double Writer分析 | 登机入口 |
| InnoDB中四种行格式分析及对varchar和char的限制 | 登机入口 |
===============================================================
前面几篇,我们分析了MySQL中索引的相关知识以及explain执行计划分析,想必大家对索引已经有了基本的认识,那么这一篇,我将为大家介绍一下MySQL中事务以及MVCC相关知识
==================================================================
事务(Transaction)是由一系列对数据库中的数据进行访问与更新的操作所组成的一个程序执行单元。
在同一个事务中所进行的操作,要么都成功,要么就什么都不做。理想中的事务必须满足四大特性,这就是大名鼎鼎的ACID。
======================================================================
并不是所有的事务都满足ACID特性,比如:对于Oracle和SQL Server数据库,其默认隔离级别是Read COMMITTED,就不满足I(隔离性)的要求;对于MySQL的NDB Cluster引擎来说,不满足D(持久性)的要求。
原子性指的是数据库事务是不可分割的一部分,只有一个事务中的所有操作都成功,这个事务才算执行成功,一旦有一个操作失败,那么其他成功的操作也必须回滚。
以转账1000元场景为例,一个转账过程就是一个事务,这个事务主要包括以下两步:
1、从A账户扣除1000元
2、将B账户中增加1000元
试想,如果第一步成功了,那么第二步失败了,那就等于A的1000元钱直接消失了,相信这是任何人都不能接受的事项,所以数据库事务才需要保证原子性。
指的是在事务开始之前和事务结束之后,数据库的完整性约束都没有被破坏,事务执行的前后都是合法的数据状态。
合法的数据库状态也包括了两种:
1、数据库自身的完整性约束。比如主键必须唯一,长度必须符合定义。
2、用户自定义的完整性约束。比如转账功能,无论两个账户之间怎么转账,最后总和应该保持不变。
隔离性就是说每个事务之间的操作应该相互隔离,互不干扰。比如说一个事务提交之前对另一个事务不可见。
隔离是一个相对抽象而复杂的概念,比如说事务之间的隔离性我们到底要隔离到哪种程度呢?所以,针对隔离,SQL92标准定义了4种隔离级别,这个放在后面事务的隔离级别中介绍。
持久性这个概念就比较容易理解了,就是说事务一旦提交成功了,那么就应该是持久的,即使是数据库重启,服务器宕机等情况发生,数据都不会丢失(当然这个不能包括因为地震等自然灾害导致的存储数据的硬盘发生不可逆的损坏)。
==================================================================
可能很多人会说自己都感知不到MySQL的事务,其实这是因为MySQL事务是默认开启了自动提交的,因此,如果要感知到事务,我们需要关闭自动提交或者显示开启事务。
查看自动提交语句:
SHOW VARIABLES LIKE ‘autocommit’;-- ON表示开启了自动提交
SELECT @@autocommit;-- 1表示开启了自动提交
执行如下语句关闭自动提交:
SET autocommit=‘OFF’;
SET @@autocommit = 0;
不过需要注意的是,这种修改方式只是在当前会话窗口生效,对其他会话窗口是不生效的,MySQL几乎所有变量设置都会分成两个级别,session(会话)和global(全局)级别,默认就是session级别。
-
START TRANSACTION或者BEGIN:显示的开启事务。需要注意的是在存储过程中只能用START TRANSACTION开启事务,因为存储过程本来有BEGIN…END语法,两者会冲突。
-
COMMIT:提交事务。也可以写成COMMIT WORK。
-
ROLLBACK:回滚事务。也可以写成ROLLBACK WORK。
-
SAVEPOINT identifier:自定义保存点,适用于长事务,可以回滚到我们自定义的位置。
-
RELEASE SAVEPOINT identifier:删除一定保存点,如果没有保存点的时候,会报错
-
ROLLBACK TO[SAVEPOINT] identifier:回滚到指定保存点。
COMMIT和COMMIT WORK的区别
这两个都能提交一个事务,区别就在于提交事务之后的操作,同样的还有ROLLBACK和ROLLBACK WORK,主要是通过一个变量来控制:completion_type,可以执行下面的sql来查看结果:
SHOW VARIABLES LIKE ‘%completion_type%’;
completion_type有如下三种结果:
| 值 | 描述 |
| — | — |
| NO_CHAIN或者0 | 默认值,此时commit和rollback等价于commit work和rollback work |
| CHAIN或者1 | 此时commit work和rollback work等价于commit and chain和rollback and chain,在提交或者回滚事务之后会立刻启动一个相同隔离级别的新事务 |
| RELEASE或者2 | 此时commit work和rollback work等价于commit release和rollback release,在提交或者回滚事务之后会断开当前数据库连接连接 |
举个栗子1:
SET completion_type=1; --1
begin;–2
INSERT test2 VALUES(1,‘张1’);–3
commit work;–4
INSERT test2 VALUES(2,‘张1’);–5
select * from test2;–6
rollback;–7
select * from test2;–8
第4条语句中,我们提交了一个事务,第5条语句中我们又插入了一条数据,此时第六条语句可以查询出2条数据,接下来我们回滚,语句8再去查询就会发现只剩一条数据了,因为语句6倍回滚了,我们在语句4之后并没有显示的开启一个事务,这就说明语句4自动开启了一个新的事务。
举个栗子2:
SET completion_type=2;
begin;
INSERT test2 VALUES(3,‘张1’);
commit work;
select * from test2;
最后一条语句返回如下结果:
先提示的断开连接,然后自动重连。测试这个例子的时候用工具比如sqlyog可能会不是很明显,因为工具会自动帮忙重连,看起来就好像没断开一样,建议用命令窗口的形式测试
==================================================================
从事务的理论角度来说,我们可以把事务分为以下五大类:
这种是最简单也是最常用的一种事务,这种事务中的所有操作都是原子的,要么全部成功,要么什么都不做。
这种一般比较适合于长事务,事务处理到后面报错的时候,我们可以选择不全部回滚事务,而是回滚到我们自定义好的某一个保存点(如果系统发生崩溃,所有的保存点都将消失)。如下例子:
BEGIN;
INSERT test VALUES(1,‘张1’);
SAVEPOINT A
INSERT test VALUES(2,‘张2’);
ROLLBACK TO A
COMMIT;
上面示例语句中,我么你定义了一个保存点A,然后在后面又回滚到A,这时候提交事务,那么第二条插入语句是失败的,而第一条语句是成功的。
注意:回滚到指定保存点之后,事务仍然还在活动状态,我们依然需要执行COMMIT或者ROLLBACK语句才算结束了事务。
在提交一个事务之后,释放掉我们不需要的数据,将必要的数据隐式的传给下一个事务。(注意:提交事务操作和开始下一个事务操作是一个原子操作)这就意味着下一个事务能看到上一个事务的结果。
链事务可以看成带有保存点的特殊事务,他们的区别就是带有保存点的事务可以回滚到任意保存点,但是回滚之后事务仍然活跃,需要执行COMMIT或者ROLLBACK之后才结束事务,而链事务中只能回滚到最近的一个保存点(即最新的一个开始事务的点)。
链事务可以通过上面的completion_type参数来实现。上文中有举例使用方法,这里就不重复举例了。
嵌套事务就是说一个事务之中嵌套另一个事务,事务之间存在父子关系,子事务的提交之后并不生效,需要等到父事务提交之后才会生效。
需要注意的是MySQL原生并不支持嵌套事务,但是可以通过保存点模拟嵌套事务,只是说这么模拟的话就没有真正的嵌套事务这么灵活。
分布式事务通常就是在分布式环境下,多个数据库下运行不同的扁平事务。多个数据库环境下运行的扁平事务就合成了一个分布式事务。
====================================================================
简称RU。这种是最低的隔离级别,等于没有隔离,基本上没有数据库会使用这个级别。一个事务可以读取到其他事务未提交的数据,这种也叫做脏读。
什么是脏读?请看下面这个例子:
左边是事务1,先查一次,查到id为1的数据name为张三,这时候事务2又来了,把张三改成了李四,然后事务1又进行了一次查询,查出来了name为李四,那么假如这时候事务2发生了回滚,也就是name还是张三,但是事务1却读到了李四,这就是脏读。
简称RC。一个事务只能读取到其他事务已提交的数据,就是说在一个事务里面,执行同样的查询,会出现两次不一样的结果。Oracle和SQL Server数据库默认的数据库隔离级别。这种隔离级别解决了脏读问题,但是会出现不可重复读的问题。
什么是不可重复读?还是看上面那个例子,假设事务2更新之后马上就提交,然后事务1第二次查询查出来的结果还是李四,只是这次就不算是脏读了,因为事务2提交了,这种就叫不可重复读,因为事务1中两次查询同一条数据结果不一样。
简称RR。这种隔离级别解决了不可重复读问题,就是说在同一个事务中,执行相同的查询,结果都是一样的,但是这种级别会出现幻读问题(InnoDB引擎例外,InnoDB引擎通过间隙锁解决了幻读问题)。
什么是幻读?请看下面这个例子:
上面图形中,事务1进行了一个范围查询,第一次只能查出一条记录,这时候事务2来插入了一条数据,然后事务1再次执行同一个查询,这时候就能查出来两条记录,也就是多了一条,给人一种幻觉,所以称之为幻读。(InnoDB通过临键锁解决了幻读问题,想详细了解的请点击这里)
说到这里,可能有人就有疑问了,因为感觉不可重复读和幻读都是读取到已提交事务的结果,好像没什么区别?确实如此,不可重复读和幻读本质上是一样的,但是不可重复读针对的是更新和删除操作,而幻读仅针对插入操作。
这种是隔离的最高级别,也就是说所有的事务都是串行执行的,也就不存在并发事务,脏读,可重复读和幻读问题自然也就没有了。
不同的隔离级别可以解决不同的问题,大致如下图:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
| — | — | — | — |
| 未提交读(Read Uncommitted) | 可能 | 可能 | 可能 |
| 已提交读(Read Committed) | 不可能 | 可能 | 可能 |
| 可重复读(Repeatable Read) | 不可能 | 不可能 | 对InnoDB不可能 |
| 串行化(Serializable) | 不可能 | 不可能 | 不可能 |
对于未提交读和已提交读大家可能都很好理解,只要控制一个事务提交之后才能对另一个事务可见,但是对于可重复读,MySQL到底是如何实现即使一个事务已经提交了,还能对另一个事务不可见呢?这就是接下来我们要讲解的MVCC了。
======================================================================
事务隔离的实现方案有两种,LBCC和MVCC
本章节开始会涉及到一些锁的概念,这个我会在下一篇文章专门讲解锁,本文不会讲解过多锁的概念。想了解的请关注我,和孤狼一起学习进步
LBCC,基于锁的并发控制,英文全称Lock Based Concurrency Control。这种方案比较简单粗暴,就是一个事务去读取一条数据的时候,就上锁,不允许其他事务来操作(当然这个锁的实现也比较重要,如果我们只锁定当前一条数据依然无法解决幻读问题)。
当前读
这个概念其实很好理解,MySQL加锁之后就是当前读。假如当前事务只是加共享锁,那么其他事务就不能有排他锁,也就是不能修改数据;而假如当前事务需要加排他锁,那么其他事务就不能持有任何锁。总而言之,能加锁成功,就确保了除了当前事务之外,其他事务不会对当前数据产生影响,所以自然而然的,当前事务读取到的数据就只能是最新的,而不会是快照数据(后文MVCC会解释快照读概念)。
LBCC方案中,如果我们的业务系统是读多写少的话,这种方案就会极大影响了效率,所以我们就有了另一种解决方案:MVCC。
MVCC,多版本的并发控制,英文全称:Multi Version Concurrency Control。就是当我们在修改数据的时候,可以为这条数据创建一个快照,后面就可以直接读取这个快照。
最后
本人也收藏了一份Java面试核心知识点来应付面试,借着这次机会可以送给我的读者朋友们:
目录:
Java面试核心知识点
一共有30个专题,足够读者朋友们应付面试啦,也节省朋友们去到处搜刮资料自己整理的时间!
Java面试核心知识点
MVCC,多版本的并发控制,英文全称:Multi Version Concurrency Control。就是当我们在修改数据的时候,可以为这条数据创建一个快照,后面就可以直接读取这个快照。
最后
本人也收藏了一份Java面试核心知识点来应付面试,借着这次机会可以送给我的读者朋友们:
目录:
[外链图片转存中…(img-2TLLDkFx-1715588853101)]
Java面试核心知识点
一共有30个专题,足够读者朋友们应付面试啦,也节省朋友们去到处搜刮资料自己整理的时间!
[外链图片转存中…(img-ELdABGU0-1715588853102)]
Java面试核心知识点