尺有所短,寸有所长;不忘初心,方得始终。
请关注公众号:星河之码
幻读【前后多次读取,数据总量不一致】
同一个事务里面连续执行两次同样的sql语句,可能导致不同结果的问题,第二次sql语句可能会返回之前不存在的行。
事务A执行多次读取操作过程中,由于在事务提交之前,事务B(insert/delete/update)写入了一些符合事务A的查询条件的记录,导致事务A在之后的查询结果与之前的结果不一致,这种情况称之为幻读。
MVCC能否解决幻读问题
首先可以明确的是,MVCC在快照读的情况下可以解决幻读问题,但是在当前读的情况下是不能解决幻读的。
mysql里面实际上有两种读取的方式:快照读和当前读,在之前的文章中《MySQL(八):MVCC多版本并发控制》也有介绍,这里重新简单回顾一下。
快照读【Consistent Read】
也叫普通读,读取的是记录数据的可见版本,不加锁,不加锁的普通select语句都是快照读,即不加锁的非阻塞读。
快照读的执行方式是生成 ReadView,直接利用 MVCC 机制来进行读取,并不会对记录进行加锁。
如下语句:
select * from table;
当前读
也称锁定读【Locking Read】,读取的是记录数据的最新版本,并且需要先获取对应记录的锁。如下语句:
SELECT * FROM student LOCK IN SHARE MODE; # 共享锁
SELECT * FROM student FOR UPDATE; # 排他锁
INSERT INTO student values ... # 排他锁
DELETE FROM student WHERE ... # 排他锁
UPDATE student SET ... # 排他锁
当我们在读取数据的时候是【快照读】的情况下是可以解决【幻读】的问题,其原理就是MVCC。
下面使用案例说明:
假设表中有三条数据,以及有两个事物A/B,A读取数据,B插入数据

#事物A:
select name from user where id > 3;
#事物B:
insert into user valus('6','edwin');
执行过程
| 时间 | 事务A | 事物C |
|---|---|---|
| 1 | 开始事务 | |
| 2 | 第一次查询:select name from user where id > 3; | |
| 6 | 开始事务 | |
| 7 | 执行插入:insert into user valus(‘6’,‘edwin’); | |
| 8 | 提交事务 | |
| 9 | 第二次查询:select name from user where id > 3; | |
| 10 | 提交事务 |
由于采用的是【快照读】的方式,在A事物开启时会产生一个版本快照,产生版本快照如下:

然后通过MVCC的【Read View】对版本快照中各个版本链中的数据进行可见性判断,读取相应的数据版本。两次查询结果都是【id=4,5】两条数据。
Read View具体可见性规则判断在之前的文章中《MySQL(八):MVCC多版本并发控制》有详细的图文详解,这里就不再赘述。
因此,即使事务B新插入了数据,由于已经生成了版本快照,也不会影响Read View的可见性规则判读,所以在【快照读】的情况下,使用MVCC不会产生幻读问题。
当我们在读取数据的时候是【当前读】的情况下,无法使用MVCC解决幻读问题。
案例说明:还是先准备几条数据,

有两个事物A/B,A先读取数据,在修改数据,最后有读取数据,B插入数据,看看结果会什么
#事物A:
select name from user where id > 3;
#事物B:
insert into user valus('6','edwin');
#事物A:
update user set name = '彬' where id = 6;
执行过程
| 时间 | 事务A | 事物C |
|---|---|---|
| 1 | 开始事务 | |
| 2 | 第一次查询:select name from user where id > 3; | |
| 6 | 开始事务 | |
| 7 | 执行插入:insert into user valus (‘6’,‘edwin’); | |
| 8 | 提交事务 | |
| 9 | 第二次查询:select name from user where id > 3; | |
| 10 | 修改数据:update user set name = ‘彬’ where id = 6; | |
| 11 | 第三次查询:select name from user where id > 3; | |
| 12 | 提交事务 |
在时间点为9的时候
事务A的【第一次】与【第二次】查询结果与上面的快照读是一样的,基于MVCC两次查询结果都是【id=4,5】两条数据。
在时间点为10的时候
事务A修改了事务B插入的数据,由于update是当前读,所以此时会读取最新的数据(包括其他已经提交的事务)。
在时间点为11的时候
事务A执行【第三次】查询,是基于当前最新版本查询的,所以会查询到事务B插入的【id=6】的数据,一共会查询到三条数据【id=4,5,6】,与前两次查询结果不同,从而产生了幻读。
在可重复读(RR)的隔离级别下,执行当前读,
案例说明:还是使用上述的数据

#事物A:
select name from user where id > 3 lock in share mode;
#事物B:
insert into user valus('6','edwin');
执行过程
| 时间 | 事务A | 事物B |
|---|---|---|
| 1 | 开始事务 | |
| 2 | 第一次查询:select name from user where id > 3 lock in share mode; | |
| 6 | 开始事务 | |
| 7 | 执行插入时发现,id>3的范围有间隙锁,插入阻塞,处于等待状态 | |
| 8 | 第二次查询:select name from user where id > 3; | |
| 9 | 提交事务 | |
| 10 | 事物A提交,间隙锁释放,执行插入:insert into user valus (‘6’,‘edwin’); | |
| 11 | 提交事务 |
事务A在执行当前读【select … lock in share mode】的时候,在【id=4,5】的记录上加了共享锁,并且在【id > 6】这个范围上也加了间隙锁,所以上图中的事务B执行插入操作时被阻塞了。所以事务A两次读取的数据是一样的。因此,在这种情况下是不会存在幻读问题。
总结:
RR隔离级别下,当前读执行如下语句时会带上锁之外,还会使用间隙锁+临键锁,锁住索引记录之间的范围,避免范围间插入记录,以避免产生幻影行记录,
SELECT * FROM student LOCK IN SHARE MODE; # 共享锁
SELECT * FROM student FOR UPDATE; # 排他锁
INSERT INTO student values ... # 排他锁
DELETE FROM student WHERE ... # 排他锁
UPDATE student SET ... # 排他锁
注意
这种方式不能解决3.1中的幻读问题,因为在3.1中事务A执行修改数据,获取锁之前,已经读取到了事务B插入的数据,并且已经记录到Undo日志中。
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search
由于fast-stemmer的问题,我很难安装我想要的任何rubygem。我把我得到的错误放在下面。Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingfast-stemmer:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcreatingMakefilemake"DESTDIR="cleanmake"DESTDIR=
当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。
导读语言模型给我们的生产生活带来了极大便利,但同时不少人也利用他们从事作弊工作。如何规避这些难辨真伪的文字所产生的负面影响也成为一大难题。在3月9日智源Live第33期活动「DetectGPT:判断文本是否为机器生成的工具」中,主讲人Eric为我们讲解了DetectGPT工作背后的思路——一种基于概率曲率检测的用于检测模型生成文本的工具,它可以帮助我们更好地分辨文章的来源和可信度,对保护信息真实、防止欺诈等方面具有重要意义。本次报告主要围绕其功能,实现和效果等展开。(文末点击“阅读原文”,查看活动回放。)Ericmitchell斯坦福大学计算机系四年级博士生,由ChelseaFinn和Chri
相信很多人在录制视频的时候都会遇到各种各样的问题,比如录制的视频没有声音。屏幕录制为什么没声音?今天小编就和大家分享一下如何录制音画同步视频的具体操作方法。如果你有录制的视频没有声音,你可以试试这个方法。 一、检查是否打开电脑系统声音相信很多小伙伴在录制视频后会发现录制的视频没有声音,屏幕录制为什么没声音?如果当时没有打开音频录制,则录制好的视频是没有声音的。因此,建议在录制前进行检查。屏幕上没有声音,很可能是因为你的电脑系统的声音被禁止了。您只需打开电脑系统的声音,即可录制音频和图画同步视频。操作方法:步骤1:点击电脑屏幕右下侧的“小喇叭”图案,在上方的选项中,选择“声音”。 步骤2:在“声
首先回顾一下拉格朗日定理的内容:函数f(x)是在闭区间[a,b]上连续、开区间(a,b)上可导的函数,那么至少存在一个,使得:通过这个表达式我们可以知道,f(x)是函数的主体,a和b可以看作是主体函数f(x)中所取的两个值。那么可以有, 也就意味着我们可以用来替换 这种替换可以用在求某些多项式差的极限中。方法: 外层函数f(x)是一致的,并且h(x)和g(x)是等价无穷小。此时,利用拉格朗日定理,将原式替换为 ,再进行求解,往往会省去复合函数求极限的很多麻烦。使用要注意:1.要先找到主体函数f(x),即外层函数必须相同。2.f(x)找到后,复合部分是等价无穷小。3.要满足作差的形式。如果是加