数据库隔离级别和各个级别下的缺点

2018 - 04 - 19 更新

今天突然感觉对 RC 下的不可重复读不太理解了,然后找了些网上的资料回顾下。比如 MySQL 四种事务隔离级的说明,发现大家在测不可重复读和可重复读的时候,都只直接用 select 去查的,也就是快照读。但是其实 RC 和 RR 下都是有 MVCC 的,自己又弄了几个例子测了测。本来理解的是无论 RC 还是 RR,只要在一个事务内的 select 都应该返回一样的结果。RC 下的不可重复读应该是对当前读来说的,RC 下的快照读本来也以为是能两次查询返回一致的。但是自己跑去测了下发现 RC 下两次读其实能读到其他事务提交的新数据,但是对数据的更新读取不到,还是只能读取到快照。

2018 - 03 - 02 更新

幻读:同一个事务的两次查询(delete insert update 触发唯一约束也算查询)第一次查没有,第二次查又有。幻体现在开始看没有,转头一看又有了,跟平时理解的幻觉有点相反。平时理解的幻觉是当时看有,之后看没有,怀疑当时出现了幻觉。

大牛何登成关于幻读的定义:

所谓幻读,就是同一个事务,连续做两次当前读 (例如:select * from t1 where id = 10 for update;),那么这两次当前读返回的是完全相同的记录 (记录数量一致,记录本身也一致),第二次的当前读,不会比第一次返回更多的记录 (幻象)。

引用自:http://hedengcheng.com/?p=771#_Toc374698320

那么幻读是不是不被允许的?

幻读其实简单说就是查询到了其他事务新增的数据。既然原理就这么简单,允许还是不允许就要看具体业务。幻读存在的情况下,同一个事务的先后两次查询,后一次查询会出现前一次没查到的数据。具体业务具体情况分析即可。

引申到 MySQL,rc 和 rr 因为有 MVCC 的存在,解决了大部分的幻读问题,没解决的部分是指下面的这个例子(delete 的情况)。但是 rc 和 rr 都还是存在幻读问题,并且 rc 还有不可重复读问题。真正的解决幻读只能用序列化的级别。

此处可以引用个资料(知乎回答):

如果实现snapshot(mysql下的repeatable read)隔离级别,读可以不加锁。保证无脏读,无更新丢失,无不可重复读(第二次读到变更的记录),排除绝大多数幻读

mysql读取数据是快照读,不加锁,那RR的防止脏读幻读是如何实现的

另外还有:

https://github.com/Yhzhtk/note/issues/42

另外 RR 下,如果第一次查询用 next-key lock 对数据加锁,那么就能在这个级别下就能实现避免幻读。但是会影响其他事务对索引的间隙内进行写入。

MVCC 与幻读的关系?

如上第二段描述。

看这个比较透彻:

https://tech.meituan.com/innodb-lock.html

Read More ...

技术学习的路径

像点样子的大公司社招都是会去招聘最好的人,就是某个领域或者多个领域有比较深的能力,然后又有一定知识广度,能独挡一面。最近尝试面了几家公司,发现了自己的很多不足,比如:

  • 很多知识一知半解、不够透彻
  • 所做项目并没有很值得述说,也就是没有亮点
  • 了解的不少,但是真正清楚明白的不多,真个的原因一方面是学习过的东西总结做得比较少,一方面是学习的时候深入理解的不够

自己一直以来的学习习惯都是随便抓一样东西,看几篇文章敲几个用例,都比较一知半解,这样是不行的。真正比较好的学习方法应该是先囊括几个领域,比如数据库、分布式计算、中间件等、JVM,然后再从这些根节点出发去学习更多相关的知识,就像是一棵树,慢慢往下衍生,越往下就越深入。当然囊括根节点的时候需要寻找几个相关的节点,如果是后端为主,那么就不要去弄什么前端了,Java图形相关也不应该涉猎。这个的原因很简单,人的精力优先,再聪明的人也无法在所有领域都能深入和精通的。更何况自己这样精力不是很多,时间上更是会受限制。

Read More ...

深入Java虚拟机笔记

GC

GC需要处理的是:哪些对象没用了需要清理、什么时候回收、如果清理

哪些对象需要清理?

判断一个对象是否需要回收有两种方式:引用计数方式、可达性分析算法

引用计数方式

对对象的引用进行计数,计数为0则是需要清理的对象,>=1则是需要持有的。无法处理的问题是在循环引用的时候是无法处理。这只是一个描述GC理论说法,其实没有真正的JVM是中这种算法实现的。

Read More ...

volatile理解

看一段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
class VolatileExample {
int a = 0;
volatile boolean flag = false;
public void writer() {
a = 1; //1
flag = true; //2
}
public void reader() {
if (flag) { //3
int i = a; //4
}
}
}

volatile的作用是让一个变量是多线程可见的,并且对他的 get 和 set 是原子的。着重考虑前一点,后一点好理解。

Read More ...

在Regin间对象相互引用时G1如何完成Root-Tracing

在Regin间对象相互引用时G1如何完成Root-Tracing

假如在对一个 Region 进行 GC,称他为 S1,上面有一个对象 O1 需要进行可达性分析。 如果没有其他 Region 上的对象引用 O1,那么皆大欢喜, 只在 S1 上就能确定 O1 是否可达(不可达就是需要清理)。如果有其他 Region 上的对象引用 O1,如果还不只一个,那么处理起来就比较麻烦了,笨办法就是去遍历,这当然不是一个好办法。

Read More ...

可达性分析算法和CardTable

可达性分析算法

可达性分析算法是用来寻找堆中哪些对象是需要被回收哪些是存活用的。他的原理是选择一些根对象作为基础,从这些根对象出发需找这些对象引用的对象。在递归寻找子对象之后,就能行程一颗庞大的树。在这棵树上的对象都是存活的,不在这课树上的对象是需要清理的。

然后说 CardTable

CardTable 是一种 JVM 实现中用到的一种数据结构。CardTable 是一个字节数组,数组中的每一位表示年老代的某一区域中的所有对象是否持有新生代对象的引用。如果持有就是 1,如果不持有就是 0。

Read More ...

博客开张啦啦啦

从大学开始就鼓捣过个人博客,当时用的是GAE,当时就搭了个博客但是没有坚持更新文章,记得随便鼓捣了几篇没什么内容的小东西就基本废弃状态了。

最近越来越热衷写文档,公司的wiki用的飞起,文档也是越写越有心的而且也觉得很有必要。自己研究和总结的东西都一致记录在wiznote里,有些东西已经稍微够得上
博文的资格,所以就鼓捣出这个个人博客。:)

Read More ...