Monthly Archive: August 2020

0

登录界面的最佳实践

假如你的网页需要用户注册/登录,那么一个好的注册/登录界面就非常重要了,尤其是在用户的网络状况不佳,或者使用移动设备,亦或是心情不太好的时候。一个不佳的界面可能会让用户再也不想访问你的页面。 下面就是一个简单的登录界面,它展示了所有的最佳实践需要关注的地方: 那么一个登录/注册界面有哪些地方需要注意的呢?我们一一道来: 使用有意义的HTML 使用下面这些HTML的tag来创建这个界面:<form><label>以及<button>,这些浏览器内建的功能,可以极大的改进可访问性。 使用<form> 你可能会使用<div>,然后在里面使用javascript来控制input的提交。其实最好还是使用原来的<form>元素。这样你的网站对屏幕阅读器或者别的辅助装备就更加友好,而且对旧的浏览器兼容也会好很多,设置在js失败的情况下也能够使用。 使用<label> 使用<label>来label一个输入: 这样做有两个原因: 当点击lable的时候,它会自动聚焦到他的输入。把label和输入关联是使用它的‘for’属性,可以设置成管理输入的name或者id。 屏幕阅读器会阅读这个文本 不要在input label中使用占位符,人们很容易忘了他们输入的是什么,究竟是email的地址,电话号码还是一个用户id。最好把你的label放在输入的上面,这样在移动设备以及桌面的体验就一致了。而且label和输入都可以得到所有的宽度,你不需要调整label和输入的宽度,如下图所示: 使用<button> 对按钮来说,使用<button>元素。因为它提供了很多特性和内置的表格提交功能,而且可以有很多不同的风格。我们没有理由选择别的<div>等来实现类似的功能。 另外对提交按钮来说,确认它究竟是做什么,比如是创建account和登录,而不是提交或者开始等。 确保正确表格的提交 要协助密码管理理解一个提交的表格,有两种方法可以做这个: 跳转到一个不同的页面。 使用History.pushState()或者History.ReplaceState()来模拟跳转,当然同时移除密码表格 在使用XMLHttpRequest或者fetch请求之后,确保登录是成功的,就需要把这个登录界面从DOM中移除,这样就可以很成功地像用户显示操作的结果。 当用户点击了之后就禁用登录按钮,因为很多用户在完成点击后还是会点击很多次,哪怕你的网页反应很快。 而另外一个方面,不要在用户没有完成输入的时候就禁用登录按钮,比如说用户没有输入密码就不让它点登录按钮,因为有时候用户自己也不知道哪里没有输入,然后就不停地在尝试。或者最起码,你禁用按钮的同时告诉用户为什么会禁用。 不要重复输入 有些网站让用户输入email和密码两次,这有可能会减少错误,但是会增加大多数用户的输入负担。尤其是很多时候浏览器自动填充了这些信息,那么输入两次就更没有意义了。更好的方式就是让用户确认他们的邮箱(反正你也肯定需要这么做),然后提供一个很方面的重置密码的方式就行。 充分利用元素属性 浏览器有很多内置的特性可以使用各种元素的属性。 帮助用户更快地开始 加一个autofocus属性到你注册表格的第一个输入,这样可以让用户知道从哪里开始,至少在桌面应用我们可以这么做,这样用户不需要点击输入框,然后再开始输入。 保护密码–但是在用户想要看到的时候可以让他们看到 密码的输入需要使用type=”password”,这样就可以隐藏输入的密码,同时也让浏览器知道输入的是密码。同时,你也需要加入显示密码的图标,这样用户可以点击它来看到自己输入的密码是多少,当然同时也不要忘记加入一个“忘记密码”的链接,如下所示: 给移动用户一个正确的键盘 使用<input...

0

如何使用AVIF:下一代图形压缩格式

一个更加优化的图形格式 目前有一个新的图形格式,它就是AV1 (.avif)格式。总得来说,它是一个高度压缩的图形类型。很多公司已经开始考虑使用.avif来替代JPEG, PNG甚至最新的WebP的图形格式,毕竟他的压缩比真的很好。 这个格式是由Alliance for Open Media与Google,Cisco以及Xiph.org一起开发的。这个格式是开源的并且免版税的。 AVIF和JEPG以及WebP的比较 AVIF和JPEG以及WebP比起来有明显更加小。和JPEG比起来小了大概50%,和WebP比起来大概小了20%。 这个格式非常灵活,支持各种图形解码器,可以使用一个alpha通道,设置能保存一系列的动画帧。 也是第一个支持HDR颜色的图形格式,能够有更好的亮度,颜色深度以及色域。 在Web开发中使用AVIF 2020年八月25号,Chrome 85已经开始支持AVIF了,Firefox 80也可以通过配置来支持了。Fixfox中的配置,可以输入下面的about:config,然后搜索image.avif.enabled,并把这个参数设置为true。 通过Squoosh来创建AVIF Squoosh是一个图形压缩web app,我们可以使用它的一些高级的选项来设置各种图形压缩。 最近Chrome Lab团队把AVIF加入到了Squoosh web app中,这大概是目前最好的创建.avif文件的方式了。 假如你对命令行有兴趣的话,你可以使用官方的AOMedia库,libavif。假如你使用macOS,可以使用Homebrew。你可以通过下面的命令来快速安装: 渐进增强的AVIF 尽管AVIF目前还不是在所有的地方都支持,我们仍然可以利用原生HTML中的<picture>元素来使用这个格式。就是把avif的格式支持放在第一位,这样浏览器就会先看能不能支持,如果不能支持会选择下面的别的格式。 AVIF Content-Type Header + Netlify 我们之前在Netlify中使用这个图片的时候,发现一个问题,就是这个图形在FireFox中不显示,但是在Chrome中使用就没有问题,最后我们才发现,response header会返回Content-Type: application/octet-stream,然后这样一来Firefox就什么不会显示。我们在Netlify的配置文件中netlify.toml中加入了下面这个自定义的header:...

你意想不到的默认超时 0

你意想不到的默认超时

有时我们会发现很多应用它不会崩溃,但是很多时候它会hang住。而hang住的一个很重要的原因就是假设网络是可靠的。而事实上却不是。 所以,当你做一个网络调用而没有设置超时的,就意味着你100%确认这个调用会成功,真的可以这么自信吗?哈哈。 假如是一个同步的调用,如果这个调用永远不返回,则显然会永远卡住。不过实际上我们都是使用的异步调用,是的,一个异步调用的不返回是不会卡住主进程的。但是有一个新的问题,就是它会消耗socket。因为很多HTTP客户端的库都使用socket池,这样就不需要每次都创建连接(毕竟创建连接是需要时间的)。一般来说,这种socket池也是有大小限制的,这也就意味着每一次不返回的调用都会消耗socket池中的一个已有的连接。所以,但这种情况发生了比较多了之后,你的应用就会卡在等待连接的释放。 假如你的网络不可靠,我们为什么总是要创建一个不超时的API呢?很多API调用甚至每有一个很方便的设置tiemout的地方,尤其是初始化的时候,你要设置timeout就需要额外进行调用。尤其是这种API很多时候默认的timeout还是无限的。当然,一个好的API都有很方便的设置timeout的方法。 所以,第一个建议就是永远不用把默认的timeout设为无限。 我们下面来看一个例子: 我们经常会使用Javascript中的XMLHttpRequest这一个web API。它的默认timeout是0,也就是没有timeout: 现代web应用中可以使用fetch来取代XMLHttpRequest API,它使用的是promise。当它刚实现的时候,根本就没有方法来设置timeout,不过最近浏览器加入了一个Abort的API来设置timeout。 其实在Python方面也是类似的,request库也默认使用无限作为timeout的。 那Go怎么样呢?其实也是一样的,默认没有timeout 当然在Java和.NET的世界则会更加好一点,它们都有默认的timeout。比如.Net Core的HttpClient有100s的默认时间,虽然很难说这个值好不好,但总归比没有好。 总结 所以总的来说,不管默认的timeout是多少,我们最好都设置自己想要的timeout。

0

十个最佳数据科学相关的Python库

我们都知道Python很流行也很易学, 本文将列出十个最佳的数据科学相关的Python库。希望对你能有所帮助。 NumPy NumPy十个主要用于数据分析,科学计算以及数据科学的库。NumPy支持多维的数组和矩阵。他是数据科学中的最基础的库之一。NumPy也被TensorFlow内部使用,并且被很多别的库所使用。很多时候,NumPy更像一个同样的Python库一样。 Pandas Pandas是另外一个Python库,它专精于数据的整理和合并。它可以方便快捷来进行数据的整理,合并和数据图形化显示。Pandas常被用来从一个CSV文件中创建数据框架。 Matplotlib Matplotlib在数据可视化中非常有用。它提供了很多种有效显示数据的方法。你可以使用它来很快速地画出曲线图,饼图,直方图以及各种各样的专业图形。你可以自定义图表中的任何部分。 Scikit-Learn Scikit-Learn是针对经典的ML算法的最动态和广泛的库之一。它是基于两个库来实现的,一个就是我们上文提到的NumPy,另外一个Scipy。它可以为大多数监督和非监督算法提供支持。这个库也可以用于数据挖掘,数据收集以及数据分析,所以它对很多ML的初学者来说也很有用。 TensorFlow TensorFlow不需要多说吧,他是一个用于机器学习应用的库,你可以实现神经网络等等各种算法。它是目前为止最流行的机器学习的库,虽然不是第一个,但自从它出现后,很快就迅速超过了所有其他的库。 Keras Keras是一个强大的Python机器学习库。它是一个高级的神经网络API,可以运行在TensorFlow,CNTK或者Theano之上。它可以独立地在GPU或者CPU上运行。对于新手来说,使用Keras非常方便和快捷。 Scrapy Scrapy是一个用于进行网络抓取的Python框架。它主要用于提取,保存和处理大量的网络数据。我们可以使用它来很方便地处理大量的数据。 Seaborn Seaborn其实是基于Matplotlib创建一个数据可视化的库。你可以使用它来整理信息性和统计性的视觉效果以及说明性图表。Seaborn是的数据可视化成为数据探索和分析不可或缺的一部分。它这个库非常适合测试多个变量之间的关系。 SciPy SciPy是一个包含各种线性代数,数学计算,优化和统计模块的库。开发者可以使用它来进行傅里叶变换,ODE求解,信号和图像处理等。 Plotly Plotly是一个开源的绘图库,它支持超过40中图形类型,基本涵盖了所有的分析,经济,地理,科学和三维用例等等各个方面。 总结 总得来说,了解上面十个Python库是你学习数据分析的重要武器,希望你们能够喜欢。

0

ShaZam深入分析之从数字声音到频率

我们在之前的文章中介绍了如何从模拟声音转变到数字声音。现在假如有了一个数字声音,你如何得到他的频率呢?这个部分很重要,因为ShaZam的算法基本都是基于频率的。 对模拟信号来说,这里有一个变化称为连续傅里叶变换。它可以把一个时间的函数转变成频率的函数。也就是假如把傅里叶变换应用到一个声音上,你就会得到它的频率。 但是这里有两个问题: 我们处理的数字信号,所以它是一个有限的不连续声音。 为了更好地理解音乐内部的频率,我们需要把傅里叶变换应用到整个音乐信号的更好的部分,比如我们需要把它应用到0.1s的部分。 还好,我们这里有一个新的数学函数,称之为离散傅里叶变换。 离散傅里叶变换 DFT(离散傅里叶变换)应用到离散信号中,并且返回一个离散的光谱。下面这里是它的公式: 这个公式中: N是窗口的大小:组成信号的样本数目 X(n)代表第n个频率区间 x(k)是音频信号中的第k个样本 例如,对一个有4096个样本的音频信号,我们需要应用这个公式4096次: n=0计算第0个频率区间 n=1计算第一个频率区间 n=2计算第二频率区间 你也许注意到,我说的是频率区间而不是频率。这是因为DFT给出的离散光谱。频率区间是DFT能够计算的最小频率单元。频率区间的大小等于信号的采样率除以窗口的大小(N)。在我们上面的例子中,有4096个窗口,标准的声音采样率是44.1kHz,所以频率分辨率就是10.77Hz (第0个有点特殊) 第0个频率区间是0Hz到5.38Hz 第一个频率区间是5.38Hz到16.15Hz 第二个频率区间是16.15Hz到26.92Hz 第三个频率区间是26.92Hz到37.68Hz 这就意味着DFT不能够区分小于10.77Hz的两个频率。比如27Hz,32Hz,37Hz其实都落在同一个频谱区间。假如37Hz的音符比较重,你只会知道第三个频率区间比较重。这个对最低八度音阶的解离其实是有问题的,比如: A1在55Hz,而B1在58.27Hz以及G1在49Hz。 标准88键的第一个音符实在A0 27.5Hz,然后后面是A#0位于29.14Hz 你可以通过增加窗口大小来改进频率分辨率,但这也意味着会丢失音乐中的快速频率/音符的改变: 一个音乐信号的采样率是44.1 kHz 增加窗口的大小意味着增加更多的样本,因此就是增加window的时间。 对于4096样本,这个window的时间就是0.1秒,频率分辨率是10.7Hz:你可以每0.1s探测一次改变 对于16384样本,这个window的时间就是0.37s,频率分辨率就是2.7Hz:你只能探测到0.37s的改变。 音频信号的一个特殊性就是只需要通过DFT计算一般的频率区间。在之前的定义中,频率区间的定义是10.7Hz,这也就意味着2047个的频率区间展现了从21902.9Hz到21913.6Hz。但是: 第2048个频率区间和第0个是一样的...

0

ShaZam深入分析之音乐数字化

除非你是发烧友,否则一般来说我们听的音乐都是数字文件,比如mp3等等。但事实上,制作音乐的时候,都是模拟的。音乐其实最终都是数字化以便于用电子设备进行存储和播放。那么本文就来讲讲如何从模拟转变成数字,了解了这些之后,会有助于我们后面的理解 采样 模拟信号其实是连续的信号,这也就意味着你可以把一秒的模拟信号分成无数份。而对数字信号来说,你不可能保存无限的数据。所以,你需要一个最小的单元,比如1毫秒。在这个单元里面,声音是不变的,所以为了能够足够接近模拟信息,这个单元需要足够小,但有不能太小,否则就需要很大的空间来存储这个数字信息。 我们可以想象一下,哪怕是你最喜欢的音乐,但是每两秒的声音都不变,这听起来估计也很奇怪。所以为了你的音乐听起来很好,你可以选择一个很小的单元,比如一个纳秒等,这时你的音乐听起来就非常赞,当然你可能没有足够的磁盘来保存这种音乐。 所以,这时候就需要使用本节的主题:采样。 标准的数字音乐是44100单元每秒,我们称之为采样率。我们在前文中提到,人耳能听到的声音范围是20Hz到20kHz。Nyquist和Shannon定理指出假如你想要数字化一个信号到0Hz到20kHz,那么你需要最少40000的采样率。主要的思想是一个F频率的正弦波需要至少每个cycle 2个点来鉴别。我们来看下面这个图: 上图中,20Hz的声音被40Hz的采样率来进行数字采样。 蓝色的波形是20Hz的声音 红色的叉就是声音的采样,也就是说每1/40秒采样一次。 绿色的线是采样声音的插值 虽然这个形状和振幅不同,但是采样信号的频率是一样的。 下面是一个坏的采样例子: 这张图中,20Hz的声音是30Hz的采样率。这个采样信号的频率和原来的信号的频率是不同的:它的频率只剩10Hz了。假如仔细看看,你会发现采样中的一个cycle是原来信号中的两个cycle。这就是采样不足的情况。 这个例子还说明一个问题:假如你想要数字化一个在0Hz到20KHz之间的信号,那么你需要先把超过20kHz的频率去除。否则这些频率会被转到0Hz到20KHz之间的信号,从而产生我们想不到的干扰。 总的来说,假如你想把一个音乐从模拟转变成数字信号,那么采样率最好40000次每秒。 量化 我们看到如何数字化频率,但是声音的大小怎么办呢?声音的大小是相对的,同样的信号,假如你把扬声器的声音调大,声音也会变大。所以响度是一首歌中最低和最高声音之间的变化。 所以这里有了一个问题,怎么把这些信息从连续的模拟信号转变成离散的量。 我们来假设你最喜欢的音乐有四个响度:没有声音,低声,高声以及最高声。当然现实不是这样的,但我们这里只是做一个例子: 下面就是这个例子的图片: 这张图显示了8个级别的量化,你可以看到声音的结果(红色)产生了很大的变化。真实声音和量化的线之间的差别我们称之为量化错误或者量化噪音。8个级别的量化我们也称为3bit量化,因为你需要3个bit来表示八个不同的级别。 下面是一个64级别的例子(6bit) 这张图中可以看出,虽然结果看起来还是有点差别,但是和原来的声音已经更加接近了。 还好人耳的声音辨识度不是太高,所以标准的量化值是16bit,也就是说65536级。也就是16bit的量化值对人耳来说已经足够低到无法分辨了。 脉冲编码调制 脉冲编码调制就是我们通常说的PCM,它是一个显示数字信号的标准。很多电子设备都使用它,比如你听mp3的时候,mp3其实会自动转换成PCM信号,然后再发送到你的耳机。 一个PCM流就是一个有组织的bit信号。它可以有多个通道,比如,立体音就需要2个通道。 在一个流中,信号的振幅被分成sample。每秒的采样数目和音乐的采样率有关。比如44.1KHz的音乐就是每秒采样44100 sample。 有很多PCM的格式,最常使用的是PCM 44.1KHz,16 bit深的立体音。这个格式每秒有44100的采样点。每个采样点有4 byte:...

0

ShaZam深入分析之音乐基础

我们都知道声音是通过空气(或水等介质)进行传播的振动,然后由人的耳朵进行解析的。比如我们听音乐,声音就是通过空气传播,然后被你的耳朵所接受。光也和声音类似,只是说这次你的耳朵没法解析它,但是你的眼睛可以。本文就来介绍一下,音乐是如何用物理、技术进行描述的。 纯音和真实的声音 所谓的纯音就是正弦波形的音。正弦波有下面这些特性: 它的频率: 每秒的循环数,它的单位是赫兹(HZ),比如100Hz = 100循环/s 它的振幅(声音的大小相关):每一个循环的大小 人耳就是通过解析这些特性来组成声音的。人耳可以听到20 Hz 到 20000Hz的声音,而随着岁数的增加,这个范围不断地在缩小。 人耳对响度的感知取决于纯音的频率,比如一个30Hz的(振幅10)纯音听起来比100Hz(振幅10)的要轻。人耳遵循心理声学模型,具体你可以参考这边文章。 上图显示的就是一个纯音的波形,它的频率是20Hz,振幅是1. 纯音在自然界并不存在,但是任何声音其实都可以看成是多个不同振幅纯音的组合。 上面这幅图,你可以看成它是由多个正弦波组成的: 一个20Hz,振幅1的正弦波 一个40Hz,振幅2的正弦波 一个80Hz,振幅1.5的正弦波 一个160Hz,振幅1的正弦波。 现实世界中的声音可能由成百上千个纯音组成。 音符 音乐其实是由一系列音符组成的,这些音符也有长短和大小。 音符可以分成八度,也就是我们常说的A,B,C,D,E,F,G或者Do,Re,Mi,Fa,Sol,La,Si。而且它们有下面这些特性: 音符的频率是上一个八度的两倍,比如说A4的(A在第四度)的频率是440Hz,它就是A3的频率(220Hz)的两倍,是A2(110Hz)的四倍。 很多乐器以八度为单位提供了高于八个音符,我们称之为半音。 对第四度音来说,这些音符的频率如下: C4(Do3) = 261.63Hz D4(Re3) = 293.67Hz E4(Mi2)...

0

最好的编程语言

我们经常会听到有人说,PHP是最好的语言,也有人会说Java才是最好的语言,很多时候这些讨论文章的唯一目的就是让我能笑一笑,其实我们大家都知道,哪有什么最好的语言,各种语言都有其擅长和不足的地方,那么在我们实际工作中,如何来选择一个最好的语言呢? 是否有性能要求 假如你有明确的性能要求,那么我们就需要来具体分析了: 秒级:任何语言都可以做到 毫秒级:任何语言,只要程序员本身过关也都可以做到 微秒级:这个量级,很多解释性语言就可以排除了(比如Python,当然它本身很好),一个很好地程序员使用JVM是可以达到这个量级的,同样的,我想C#应该也是可以做到的。当然,纯编译语言也是可以做到的。 纳秒级:大概只有汇编或者C能够做到了。 生态系统是怎样的 其实除了语言本身,它的生态系统也很重要。比如说我们使用Visual Studio,然后你会发现很多人使用它,它的生态系统很赞。相应的工具很重要,比如Eclipse,VsCode,他们都有很多各种各样的插件可以使用,这样一来,相关语言的开发就会省力很多。 线上帮助 我们都知道,哪怕你对一个语言再熟悉,也有不懂得地方,这个时候就需要去Google或者StackOverflow上进行查询和提问,这个时候,一个热门的语言会有很多人遇到类似的问题,这无疑对你的工作是有所帮助的。 团队成员的技能 很多时候,我们要使用的不是一个最好的,而是一个大家都熟悉的,尤其是使用团队成员了解并喜爱的语言可以极大地提升工作效率和激情。 商业方面的考虑 一个很现实的问题,就是你可能会选择一个需求量最大的语言,而不是最好的语言。毕竟这样一来,至少你换工作的时候能够有所帮助。从另一个方面来说,假如你是一个tech leader,你选择了一个“最好的”语言,但是没什么人会,你想招一个有相关经验的人可能都招不到。 不过总得来说,没有什么最好的语言,只有最合适的语言。归根结底,语言只是我们的工具,我们的目标是解决问题,针对问题来进行选择,也许这才是正确的做法。

如何通过基于OAuth的API连接Vue.js 0

如何通过基于OAuth的API连接Vue.js

很多人都使用过基于OAuth的API,比如你在一些网站使用GitHub登录的时候,你就使用GitHub提高的OAuth2 API,或者你使用Google或者Facebook登录的时候,你也会使用到它。 现在OAuth真的无处不在,也许因为它真的非常好,用户只要点一个按钮,然后得到权限,这样就可以了。 但是当我们进行开发它的时候,就是另外 一个故事了,也许是因为它一次性引入了太多的新的内容。本文我们会介绍一个小的工具Bearer.sh Pizzly,有了它之后开发OAuth就方便多了。 首先来看看它长什么样子: 下面我们来看看如何使用它。 Vue.js skeleton 为了学习如何使用基于OAuth的API,我们首先需要一个Vue.js skeleton,或者至少需要一个能使用OAuth2 API的应用。 假如你已经有了GitHub的账户,我们可以使用它的API,当然别的基于OAuth的API也是可以的。 GitHub API提供了一个端口(/user/starred)列出了用户的所有的repositories。这个端口是需要authentication的,所以听起来是一个很好的使用场景。 下面是一个简单的应用代码: 这个应用代码是一个很简单的Vue.js,假如user变量已经设置了,就会显示repositories的内容个,否则就要求用户连接GitHub。 认证的部分 我们使用开源的Pizzly,它使用了.connect的方法来从前端触发认证。我们来看看如何在上面代码中加入这个内容: 是不是很简单,只要几行代码就完成了。 配置部分 在上面的代码中有一个最重要的部分就是Pizzly的初始化,这里就要提到Pizzly其实需要一个Oauth Manager,也就是说你需要把它托管在某一个地方,比如Heroku等。当这个托管完成之后,你就可以使用Pizzly的仪表板了,这也是你配置你的GitHub的地方: 总结 这样你就可以在Vue.js中使用任何基于OAuth的API了,关于任何Pizzly的意见,欢迎大家提出。 参考文章:https://hackernoon.com/connecting-vuejs-with-oauth-based-api-ks1v3ucj

0

关系型数据库进阶之Log Manager

我们在之前的文章中聊到,数据库为了提高它的性能,会把数据存在memory buffer中。但是这里有一个问题,就是假如一个已经committed的transaction crash掉了,你因为这个crash丢掉了memory中的数据,那就会出现了Durability的问题。当然你也可以把所有的数据都写到磁盘中,但是同样的问题,假如写到一半就crash了,这里就会发生原子性的问题。 所以这里的我们的原则是任何通过transaction进行写的修改都要么是全部完成要么就是什么都不做。 为了解决这个问题,有两个方法: Shadow copies/pages: 每一个transaction都创建它自己的数据库(或者部分数据库)备份,然后在这个备份上进行操作。假如有错误,这个备份就移除掉。假如成功了,就切换到这个备份上,而把旧的备份删除掉。 Transaction log:transaction log是一个存储空间。在把数据写到磁盘之前,数据库把相关的信息写到transaction info中,因此即使有crash或者cancel的时候,数据库也知道怎么来完成或者移除响应的没有完成的transaction。 WAL Shadow copies/pages的思想其实很好,唯一的问题就是在大的数据库中,会额外浪费很多磁盘的空间。这也是为什么现在主流的数据库都是用transaction log来解决这个问题。Transaction log必须存储在一个稳定的存储空间中。 大多数数据库(至少Oracle, SQL Server,DB2, PostgreSQL, MySQL以及SQLite)都使用Write-Ahead Logging protocol (WAL)来处理transaction log。这个protocol主要有三个规则: 每一个对数据库的修改都产生一个log记录,并且log记录必须在数据写到磁盘前写到transaction log中。 log记录必须按照顺序写,也就是说发生在记录A先发生,那么记录A就必须先写。 当一个transaction committed了,这个commit的顺序必须在transaction介绍前写到transaction log中 这些工作都是在log manager中处理的,他位于cache...