今天才认识到原来JPEG文件有两种保存方式他们分别是Baseline JPEG(标准型)和Progressive JPEG(渐进式)。

两种格式有相同尺寸以及图像数据,他们的扩展名也是相同的,唯一的区别是二者显示的方式不同。 Baseline JPEG 这种类型的JPEG文件存储方式是按从上到下的扫描方式,把每一行顺序的保存在JPEG文件中。打开这个文件显示它的内容时,数据将按照存储时的顺序从上到下一行一行的被显示出来,直到所有的数据都被读完,就完成了整张图片的显示。如果文件较大或者网络下载速度较慢,那么就会看到图片被一行行加载的效果,这种格式的JPEG没有什么优点,因此,一般都推荐使用Progressive JPEG。

阅读全文 »

以前做过一个人人网的站内应用(http://apps.renren.com/rr_timer不过已经很久没更新了),其中就用到了OAtuth授权,今天要做个新浪微博授权登陆,那么正巧再复习一下OAuth认证和授权原理吧,也没多少时间写这玩意儿,网上之前看到一篇不错的就拉过来了。 OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。 本文对OAuth 2.0的设计思路和运行流程,做一个简明通俗的解释,主要参考材料为RFC 6749bg2014051201

阅读全文 »

此前安装过python,但因为安装pip过程中遇到了问题,所以把python也一起卸载了。现在重新安装一下这两个。 这里选择了python2.7.8版本进行安装,因为我需要使用sqlmap这个工具,而这个工具对python版本有要求,最新版本的python会出错,所以我选择了2.7.8的版本。 首先上官网https://www.python.org/downloads 下载

QQ截图20141118141425

下载的是msi文件,直接打开像安装普通软件一样安装就行。但有一点一定要注意,如果你要使用pip,则安装python时选择的安装路径目录中不要有空格,如果安装到了Program Files这样的目录下,那么接下来安装的pip将无法正常运行,会报错。所以这里我直接选择了D盘下,安装前记得选择将python.exe添加到系统环境变量。 QQ图片20141118142038   安装完之后在CMD中输入python命令会看到欢迎界面。 接下来安装pip,上https://pip.pypa.io/en/latest/installing.html下载 get-pip.py脚本 在CMD下找到该文件目录并运行下列命令(需要管理员权限): python get-pip.py QQ截图20141118142644 安装好之后,会发现python安装目录下会多出一个Scripts目录(若之前没有)。 这时我们直接在命令行输入pip,会显示‘pip’不是内部命令,也不是可运行的程序。因为我们还没有添加环境变量。 只要在PATH变量中添加:D:\Python27\Scripts;(路径自己更换)就好了,输入pip list 查看安装情况 QQ截图20141118143306   如果出现下列错误,那么原因可能就是上面我所说的python安装路径目录名中有空格了  

Fatal error in launcher: Unable to create process using ‘“D:\Program Files\Python27\python.exe” “D:\Program Files\Python27\Scripts\pip.exe” ‘

  (完)

刚在写sql的时候思考了一下在不确定条件因素时的情况,之前看到别人使用过where 1=1这个条件, 这个条件始终为True,后来了解到在不定数量查询条件情况下,1=1可以很方便的规范语句。

一、不用where  1=1  在多条件查询中的困扰

  举个例子,如果您做查询页面,并且,可查询的选项有多个,同时,还让用户自行选择并输入查询关键词,那么,按平时的查询语句的动态构造,代码大体如下:

$sql=”select * from table where”;
if(!empty($age))
{
$sql .= ‘age=’.$age’;
}
if(!empty($address))
{
  $sql. = ‘and address=’.$address;
}

如果上述的两个if判断语句,均为true,即用户都输入了查询词,那么,最终的$sql动态构造语句变为: $sql= ‘select * from table where age=20 and address=”常州”‘; 可以看得出来,这是一条完整的正确的SQL查询语句,能够正确的被执行,并根据数据库是否存在记录,返回数据。 ②种假设 如果上述的两个if判断语句不成立,那么,最终的$sql动态构造语句变为: $sql  = ‘select * from table where’; 现在,我们来看一下这条语句,由于where关键词后面需要使用条件,但是这条语句根本就不存在条件,所以,该语句就是一条错误的语句,肯定不能被执行,不仅报错,同时还不会查询到任何数据。 上述的两种假设,代表了现实的应用,说明,语句的构造存在问题,不足以应付灵活多变的查询条件。

二、使用 where  1=1  的好处

假如我们将上述的语句改为:

$sql=”select * from table where 1=1”;
if(!empty($age))
{
$sql .= ‘ and age=’.$age’;
}
if(!empty($address))
{
  $sql. = ‘and address=’.$address;
}

①种假设 如果两个if都成立,那么,语句变为: $sql = ‘select * from table where 1=1 and age=12 and address=”常州’”,很明显,该语句是一条正确的语句,能够正确执行,如果数据库有记录,肯定会被查询到。 ②种假设 如果两个if都不成立,那么,语句变为: $sql = ‘select * from table where 1=1’,现在,我们来看这条语句,由于where 1=1 是为true的语句,因此,该条语句语法正确,能够被正确执行,它的作用相当于:$sql = ‘select * from table’,即返回表中所有数据。 言下之意就是:如果用户在多条件查询页面中,不选择任何字段、不输入任何关键词,那么,必将返回表中所有数据;如果用户在页面中,选择了部分字段并且输入了部分查询关键词,那么,就按用户设置的条件进行查询。 说到这里,不知道您是否已明白,其实,where 1=1的应用,不是什么高级的应用,也不是所谓的智能化的构造,仅仅只是为了满足多条件查询页面中不确定的各种因素而采用的一种构造一条正确能运行的动态SQL语句的一种方法。 where 1=0; 这个条件始终为false,结果不会返回任何数据,只有表结构,可用于快速建表 “select * from table where 1=0”; 该select语句主要用于读取表的结构而不考虑表中的数据,这样节省了内存,因为可以不用保存结果集。 create table newtable as select * from oldtable where 1=0;  创建一个新表,而新表的结构与查询的表的结构是一样的。

6310d41cjw1em0lsear2xg20b408cn22

起初,网页设计者都会设计固定宽度的页面,最开始的电脑显示器分辨率种类不多,因为当时电脑本来就少,即使有变化也是 800 850 870 880。 后来随着显示器越来越多,以及笔记本的普及,这种方式的页面出现了问题。于是出现了一种新的布局方式宽度自适应布局。我们平时谈论的自适应布局,大多指的就是宽度自适应布局。 在这种布局下,出现了两派:

  • 百分比宽度布局
  • 流式布局

题主说的是第一派,宽度使用百分比,文字使用em。第二派的布局以 iGoogle 为代表(已经停止)。 再后来,浏览器大战 时代,firefox、Oparo、Chrome …… 出现,结束了 IE 一统江湖的局面,N 年没有更新的 IE6 发布了新版本,以前已 IE 为标准的 CSS 向 W3C 标准趋近,随后各种针对浏览器的 css hack 技术出现。 虽然浏览器这么多,但是响应式布局依然不是主流,人们还在使用 css hack 技术。注意我的用词——「不是主流」,虽然不是主流,不代表当时不被使用。 比如一向超前的伟大的 Google。当时没有响应式布局这个词语,但是慢慢出现了一个词——渐进增强,新词的出现总是伴随的旧词一起出现。就好比 3G 出现之前,没人管自己的手机叫 2G,所以,3G 和 2G 两个词是一起出现的(技术上当然2G技术先出现)。同理,渐进增强出现后,另一个词「优雅降级」也随之出现了。 词的意思可以自己看 wiki、Google,我只在这儿举一个例子,gmail 和 qqmail。 他俩的宽度都是 100%,都是自适应。但是: qqmail 就是 css hack 的完美体现,你用任何一个浏览器,几乎可以看到同一个样子的邮箱,腾讯的前端工程师们用各种 css hack 技术来展示邮箱页面,为的是统一的用户体验。 而 gmail 使用了渐进增强,你的浏览器越强,你看到的效果就越好,用户体验就越好。 再后来,就是大家都熟知的 Google 发布了 android,于是互联网大战从 PC 打到了手机。还有 HTML5 标准的发布。 手机虽然屏幕变小了,但是却提供了更丰富的功能。还记得以前用诺基亚上 QQ 的事儿吗?我们访问的是 3g.qq.com,当时我使用的是中兴的手机,访问 wap.qq.com,在后来的职能手机都是访问 m.qq.com。 不禁有人问「真的需要为每个手机分别设计一个网页吗?」、「真的需要为手机和电脑设计不同的网页吗?」,解决方法当然有很多种,可以看看 css zen garden 相信做过前端的都看过这个网站,一个神奇的网站。 最终的解决方案胜出者是响应式布局。 响应式布局被大家熟知的一个重要原因就是 twitter 开源了 bootstrap。Google 第一次完成了从先驱到烈士。 好了,上面介绍的是从从“自适应”到“响应式”,以下 Responsive design = RWD,Adaptive design = AWD。 先说共同点,两者都是因为越来越多的 移动设备( mobile, tablet device )加入到互联网中来而出现的为移动设备提供更好的体验的技术。用技术来使网页适应从小到大(现在到超大)的不同分辨率的屏幕。有人说,RWD 是 AWD 包含的一个子集。 RWD:Ethan Marcote 的文章是大家认为 RWD 的起源。他提出的 RWD 是采用 CSS 的 media query 技术,配合流体布局( fluid grids )和同样可以自适应的图片/视频等资源素材。以上所说,都是通过 HTML 和 CSS 就能完成的。一般来说,RWD 倾向于只改变元素的外观布局,而不大幅度改变内容。Jeffrey Zeldman 总结说,我们就把 RWD 定义为一切能用来为各种分辨率和设备性能优化视觉体验的技术吧。 AWD:Adaptive Design 是 Aaron Gustafson 的书的标题。他认为 AWD 在包括 RWD 的 CSS media query 技术以外,也要用 Javascript 来操作 HTML 来更适应移动设备的能力。AWD 有可能会针对移动端用户减去内容,减去功能。AWD 可以在服务器端就进行优化,把优化过的内容送到终端上。AWD 通常会牵扯到另外一个词 “progressive enhancement” 。 progressive enhancement(渐进增强):从针对最低端的,最低分辨率的设备的设计做起,逐步逐步为更高阶的设备增加功能和效果的做法。(换个角度说,也就是相当于为移动设备减去功能) RWD 和 AWD 在断点( break point )的区别: RWD 采用流体+断点,在断点之间,页面依然会随窗口大小自动缩放(通过 fluid grid ),直到遇到断点改变界面样式。相对的,AWD 只在针对几种分辨率(如1280,800,640,320px)进行优化,在断点之间的自动过渡比较少。 还有一种说法: RWD 一般来说需要在网页设计初期就开始(通常采用 mobile first 策略),所以旧的网站要做 RWD 很可能要完全重建。而 AWD 则采用保留现有桌面网站( desktop version )而对于更小的分辨率做针对性的优化(适应),这点对于很多老的网站来说很重要,因为重构成本太大。 另外,对于 mobile 用户的优化到底应该怎么做,有两方的说法各不相让。有人说,不应该因为用户使用的是 mobile device 就删去内容,限制他们的功能,应该平等对待。也有人说,正因为是移动设备,有其流量,性能,网速的局限性,用移动设备登录网站的目的也会更有针对性,要为 用户精简文字,精简最常用的功能放在首页,服务器端的优化才是真的针对 mobile 的优化。 最后: 在网上的各种说法里确实是有很多相互干扰相互矛盾的地方,但是其实技术都是摆在那里的。其实可以认为,AWD 在针对布局的优化中,可以采用 RWD 的策略,但是AWD 着力于更多其他的 JS 或者服务器上的优化,来强化移动端体验。 不用纠结于词汇,根据网站功能复杂度,预算和资源等,选择要使用的技术,从客户端的展现,到 JS,到服务器的优化等等。

今天试用了一下facebook的php性能调试工具xhprof,在安装的时候是一波三折,虽说从百度了安装方法,但也折腾了半天,不知是说明没写全还是我个人操作失误,那么我在这把我的安装方法讲述一下。环境是:Linux+Nginx+PHP

#cd /tmp
#mkdir xhprof
#cd xhprof
#wget http://pecl.php.net/get/xhprof-0.9.4.tgz
//解压
#tar zxf xhprof-0.9.4.tgz
#cd xhprof-0.9.4/extension
//拷贝xhprof_html和xhprof_lib两个文件夹至可访问的web目录下,我的web根目录为/home/www
#cp -r xhprof_html xhprof_lib /home/www
//运行phpize
#/usr/local/webserver/php/bin/phpize
//运行configure为下一步编译做准备,详情了解Linux下的configure命令
#./configure –with-php-config=/usr/local/php/bin/php-config
#make
#make install

安装完后你会看到一个提示Installing shared extensions /usr/local/php/lib/php/extensions/no-debug-non-zts-20060626/xhprof.so,说明xhprof.so这个模块被生成了 接下来修改php.ini文件,添加:

//添加xhprof.so这个扩展,位置就是刚才生成给你的
extension=/usr/local/php/lib/php/extensions/no-debug-non-zts-20060626/xhprof.so
//指定生成测试报告分析日志的目录,并保证可写权限
xhprof.output_dir=/home/www/tmp

重启php-fpm重新加载php配置文件 #/etc/init.d/php-fpm restart 至此安装完毕,可以搞个phpinfo();页面看看,如果能看到下图则说明安装成功了QQ截图20141103143752  

xhprof的使用

写一个php脚本如

xhprof_enable();
function test()
{
return ‘this is a test demo’;
}
test();
$xhprofData = xhprof_disable();
include_once ‘/home/www/houseinfo/xhprof_lib/utils/xhprof_lib.php’;
include_once ‘/home/www/houseinfo/xhprof_lib/utils/xhprof_runs.php’;
$xhprofRuns = new XHProfRuns_Default();
$xhprofRuns->save_run($xhprofData,’xhprof_foo’);
?>

通过URL访问该脚本后,会在之前设定的/home/www/tmp(php.ini中设定的)目录下生成分析日志,如“5457280fd8500.xhprof_foo.xhprof” 其中5457280fd8500为日志生成的id,通过地址http://YOUR\_URL/xhprof_html/index.php?run=**5457315580b0e**&source=xhprof_foo即可查看性能分析(如下图) QQ截图20141103154222 你可以将上面php代码最后一行改为这样,以便直接点击链接到分析页查看,而无需自己再查看id并拼接成URL访问

save\_run($xhprofData,'xhprof_foo'); echo '查看分析报告'; ?>

xhprof提供3种报告: 一、单一运行报告:通过http://YOUR\_URL/xhprof\_html/index.php?run=**5457315580b0e**&source=xhprof\_foo地址查看的单一运行时的报告 二、diff报告:地址如http://YOUR\_URL/xhprof_html/index.php?run1=**xxxxxx**&run2=**xxxxxxx**&source=xhprof\_foo,提供两次对比id即可。 三、汇总报告,指定一组run id来汇总得到您想要的报告视图。如果你有三个XHProf运行,都在”xhprof_foo‘命名空间下,run id分别是1,2,3。要查看这些运行的汇总报告:http://YOUR\_URL/xhprof\_html/index.php?run**=1,2,3**&source=xhprof_foo XHProf输出说明 1. Inclusive Time : 包括子函数所有执行时间。 2. Exclusive Time/Self Time : 函数执行本身花费的时间,不包括子树执行时间。 3. Wall Time : 花去了的时间或挂钟时间。 4. CPU Time : 用户耗的时间+ 内核耗的时间 5. Inclusive CPU : 包括子函数一起所占用的CPU 6. Exclusive CPU : 函数自身所占用的CPU 可是这个界面看起来不是很直观也不爽,我们还可以装一个graphviz画图工具

#wget http://www.graphviz.org/pub/graphviz/stable/SOURCES/graphviz-2.28.0.tar.gz
#tar -zxvf graphviz-2.28.0.tar.gz
#cd graphviz-2.28.0
#./configure
#make
#make install

安装完成后,会生成/usr/local/bin/dot文件,确保路径在PATH环境变量里,以便XHProf能找到它,graphviz处于**/usr/local/lib/graphviz**。 #vi ~/.bash_profile QQ截图20141104133618#echo $PATH 输出一下看看应该有了这个路径 QQ截图20141104135151 之后进入分析页面点击[View Full Callgraph]就能看到类似下图了

callgraph

一、inode是什么?

理解inode,要从文件储存说起。

文件储存在硬盘上,硬盘的最小存储单位叫做”扇区”(Sector)。每个扇区储存512字节(相当于0.5KB)。

 

操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个”块”(block)。这种由多个扇区组成的”块”,是文件存取的最小单位。”块”的大小,最常见的是4KB,即连续八个 sector组成一个 block。

 

文件数据都储存在”块”中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode,中文译名为”索引节点”。

 

二、inode的内容

inode包含文件的元信息,具体来说有以下内容:

  * 文件的字节数

  * 文件拥有者的User ID

  * 文件的Group ID

  * 文件的读、写、执行权限

  * 文件的时间戳,共有三个:ctime指inode上一次变动的时间,mtime指文件内容上一次变动的时间,atime指文件上一次打开的时间。

  * 链接数,即有多少文件名指向这个inode

  * 文件数据block的位置

 

可以用stat命令,查看某个文件的inode信息:

stat example.txt

 

总之,除了文件名以外的所有文件信息,都存在inode之中。至于为什么没有文件名,下文会有详细解释。

 

三、inode的大小

inode也会消耗硬盘空间,所以硬盘格式化的时候,操作系统自动将硬盘分成两个区域。一个是数据区,存放文件数据;另一个是inode区(inode table),存放inode所包含的信息。

每 个inode节点的大小,一般是128字节或256字节。inode节点的总数,在格式化时就给定,一般是每1KB或每2KB就设置一个inode。假定 在一块1GB的硬盘中,每个inode节点的大小为128字节,每1KB就设置一个inode,那么inode table的大小就会达到128MB,占整块硬盘的12.8%。

 

查看每个硬盘分区的inode总数和已经使用的数量,可以使用df命令。

df -i

查看每个inode节点的大小,可以用如下命令:

sudo dumpe2fs -h /dev/hda | grep “Inode size”

由于每个文件都必须有一个inode,因此有可能发生inode已经用光,但是硬盘还未存满的情况。这时,就无法在硬盘上创建新文件。

 

四、inode号码

每个inode都有一个号码,操作系统用inode号码来识别不同的文件。

 

这 里值得重复一遍,Unix/Linux系统内部不使用文件名,而使用inode号码来识别文件。对于系统来说,文件名只是inode号码便于识别的别称或 者绰号。表面上,用户通过文件名,打开文件。实际上,系统内部这个过程分成三步:首先,系统找到这个文件名对应的inode号码;其次,通过inode号 码,获取inode信息;最后,根据inode信息,找到文件数据所在的block,读出数据。

使用ls -i命令,可以看到文件名对应的inode号码:

ls -i example.txt

 

五、目录文件

Unix/Linux系统中,目录(directory)也是一种文件。打开目录,实际上就是打开目录文件。

 

目录文件的结构非常简单,就是一系列目录项(dirent)的列表。每个目录项,由两部分组成:所包含文件的文件名,以及该文件名对应的inode号码。

 

ls命令只列出目录文件中的所有文件名:

ls /etc

ls -i命令列出整个目录文件,即文件名和inode号码:

ls -i /etc

如果要查看文件的详细信息,就必须根据inode号码,访问inode节点,读取信息。ls -l命令列出文件的详细信息。

ls -l /etc

 

六、硬链接

一 般情况下,文件名和inode号码是”一一对应”关系,每个inode号码对应一个文件名。但是,Unix/Linux系统允许,多个文件名指向同一个 inode号码。这意味着,可以用不同的文件名访问同样的内容;对文件内容进行修改,会影响到所有文件名;但是,删除一个文件名,不影响另一个文件名的访 问。这种情况就被称为”硬链接”(hard link)。

ln命令可以创建硬链接:

ln 源文件 目标文件

运 行上面这条命令以后,源文件与目标文件的inode号码相同,都指向同一个inode。inode信息中有一项叫做”链接数”,记录指向该inode的文 件名总数,这时就会增加1。反过来,删除一个文件名,就会使得inode节点中的”链接数”减1。当这个值减到0,表明没有文件名指向这个inode,系 统就会回收这个inode号码,以及其所对应block区域。

 

这里顺便说一下目录文件的”链接数”。创建目录时, 默认会生成两个目录项:”.”和”..”。前者的inode号码就是当前目录的inode号码,等同于当前目录的”硬链接”;后者的inode号码就是当 前目录的父目录的inode号码,等同于父目录的”硬链接”。所以,任何一个目录的”硬链接”总数,总是等于2加上它的子目录总数(含隐藏目录),这里的 2是父目录对其的“硬链接”和当前目录下的”.硬链接“。

 

七、软链接

除了硬链接以外,还有 一种特殊情况。文件A和文件B的inode号码虽然不一样,但是文件A的内容是文件B的路径。读取文件A时,系统会自动将访问者导向文件B。因此,无论打 开哪一个文件,最终读取的都是文件B。这时,文件A就称为文件B的”软链接”(soft link)或者”符号链接(symbolic link)。

 

这 意味着,文件A依赖于文件B而存在,如果删除了文件B,打开文件A就会报错:”No such file or directory”。这是软链接与硬链接最大的不同:文件A指向文件B的文件名,而不是文件B的inode号码,文件B的inode”链接数”不会因此 发生变化。

 

ln -s命令可以创建软链接。

ln -s 源文文件或目录 目标文件或目录

 

八、inode的特殊作用

由于inode号码与文件名分离,这种机制导致了一些Unix/Linux系统特有的现象。

  1. 有时,文件名包含特殊字符,无法正常删除。这时,直接删除inode节点,就能起到删除文件的作用。

  2. 移动文件或重命名文件,只是改变文件名,不影响inode号码。

  3. 打开一个文件以后,系统就以inode号码来识别这个文件,不再考虑文件名。因此,通常来说,系统无法从inode号码得知文件名。

      第3点使得软件更新变得简单,可以在不关闭软件的情况下进行更新,不需要重启。因为系统通过inode号码,识别运行中的文件,不通过文件名。更新的时 候,新版文件以同样的文件名,生成一个新的inode,不会影响到运行中的文件。等到下一次运行这个软件的时候,文件名就自动指向新版文件,旧版文件的 inode则被回收。

  九 实际问题 在一台配置较低的Linux服务器(内存、硬盘比较小)的/data分区内创建文件时,系统提示磁盘空间不足,用df -h命令查看了一下磁盘使用情况,发现/data分区只使用了66%,还有12G的剩余空间,按理说不会出现这种问题。 后来用df -i查看了一下/data分区的索引节点(inode),发现已经用满(IUsed=100%),导致系统无法创建新目录和文件。     查找原因: /data/cache目录中存在数量非常多的小字节缓存文件,占用的Block不多,但是占用了大量的inode。   解决方案: 1、删除/data/cache目录中的部分文件,释放出/data分区的一部分inode。 2、用软连接将空闲分区/opt中的newcache目录连接到/data/cache,使用/opt分区的inode来缓解/data分区inode不足的问题: ln -s /opt/newcache /data/cache   转自: http://www.ruanyifeng.com/blog/2011/12/inode.html http://blog.s135.com/post/295/ http://hi.baidu.com/leejun_2005/blog/item/d9aa13a53b3af6e99152ee7e.html

     100除以7的余数是2,意思就是说把100个东西七个七个分成一组的话最后还剩2个。余数有一个严格的定义:假如被除数是a,除数是b(假设它们 均为正整数),那么我们总能够找到一个小于b的自然数r和一个整数m,使得a=bm+r。这个r就是a除以b的余数,m被称作商。我们经常用mod来表示 取余,a除以b余r就写成a mod b = r。

    如果两个数a和b之差能被m整除,那么我们就说a和b对模数m同余(关于m同余)。比 如,100-60除以8正好除尽,我们就说100和60对于模数8同余。它的另一层含义就是说,100和60除以8的余数相同。a和b对m同余,我们记作 a≡b(mod m)。比如,刚才的例子可以写成100≡60(mod 8)。你会发现这种记号到处都在用,比如和数论相关的书中就经常把a mod 3 = 1写作a≡1(mod 3)。

    之所以把同余当作一种运算,是因为同余满足运算的诸多性质。比如,同余满足等价关系。具体地说,它满足自反性(一个数永远和自己同余)、对称性(a和b同余,b和a也就同余)和传递性(a和b同余,b和c同余可以推出a和c同余)。这三个性质都是显然的。

     同余运算里还有稍微复杂一些的性质。比如,同余运算和整数加减法一样满足“等量加等量,其和不变”。小学我们就知道,等式两边可以同时加上一个相等的数。例 如,a=b可以推出a+100=b+100。这样的性质在同余运算中也有:对于同一个模数m,如果a和b同余,x和y同余,那么a+x和b+y也同余。在 我看来,这个结论几乎是显然的。当然,我们也可以严格证明这个定理。这个定理对减法同样有效。 性质:如果a≡b(mod m),x≡y(mod m),则a+x≡b+y(mod m)。 证 明:条件告诉我们,可以找到p和q使得a-mp = b-mq,也存在r和s使得x-mr = y-ms。于是a-mp + x-mr = b-mq + y-ms,即a+x-m(p+r) = b+y-m(q+s),这就告诉我们a+x和b+y除以m的余数相同。 容易想到,两个同余式对应相乘,同余式两边仍然相等: 如果a≡b(mod m),x≡y(mod m),则ax≡by(mod m)。 证明:条件告诉我们,a-mp = b-mq,x-mr = y-ms。于是(a-mp)(x-mr) = (b-mq)(y-ms),等式两边分别展开后必然是ax-m(…) = by-m(…)的形式,这就说明ax≡by(mod m)。 现在你知道为什么有的题要 叫你“输出答案mod xxxxx的结果”了吧,那是为了避免高精度运算,因为这里的结论告诉我们在运算过程中边算边mod和算完后再mod的结果一样。假如a是一个很大的数, 令b=a mod m,那么(a * 100) mod m和(b * 100) mod m的结果是完全一样的,这相当于是在a≡b (mod m)的两边同时乘以100。这些结论其实都很显然,因为同余运算只关心余数(不关心“整的部分”),完全可以每一次运算后都只保留余数。因此,整个运算过 程中参与运算的数都不超过m,避免了高精度的出现。 在证明**Fermat小定理**时,我们用到了这样一个定理: 如果ac≡bc(mod m),且c和m互质,则a≡b(mod m) (就是说同余式两边可以同时除以一个和模数互质的数)。 证明:条件告诉我们,ac-mp = bc-mq,移项可得ac-bc = mp-mq,也就是说(a-b)c = m(p-q)。这表明,(a-b)c里需要含有因子m,但c和m互质,因此只有可能是a-b被m整除,也即a≡b(mod m)。

  原文地址:http://www.matrix67.com/blog/archives/236

数据库事务概念

数据库事务必须同时满足 4 个特性:原子性(Atomic)、一致性(Consistency)、隔离性(Isolation)和持久性(Durabiliy),简称为ACID。下面是对每个特性的说明。

  • 原子性:表示组成一个事务的多个数据库操作要么全部成功、要么全部失败。
  • 一致性:事务操作成功后,数据库所处的状态和它的业务规则是一致的,即数据不会被破坏。如从A账户转账100元到B账户,不管操作成功与否,A和B的存款总额是不变的。
  • 隔离性:在并发数据操作时,不同的事务拥有各自的数据空间,它们的操作不会对对方产生干扰。准确地说,并非要求做到完全无干扰,数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性越好,但并发性越弱。
  • 持久性:一旦事务提交成功后,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证能够通过某种机制恢复数据。

其实这四个特性,原子性是最终目的。  

数据并发的问题

一个数据库可能拥有多个访问客户端,这些客户端都可以并发方式访问数据库。数据库中的相同数据可能同时被多个事务访问,如果没有采取必要的隔离措施,就会导致各种并发问题,破坏数据的完整性。这些问题可以归结为5类,包括3类数据读问题( 脏读、 不可重复读和 幻象读)以及2类数据更新问题( 第一类丢失更新和 第二类丢失更新)。下面,我们分别通过实例讲解引发问题的场景。

脏读(dirty read)

A事务读取B事务尚未提交的更改数据,并在这个数据的基础上操作。如果恰巧B事务回滚,那么A事务读到的数据根本是不被承认的。来看取款事务和转账事务并发时引发的脏读场景: 15150645_B8Se   在这个场景中,B希望取款500元而后又撤销了动作,而A往相同的账户中转账100元,就因为A事务读取了B事务尚未提交的数据,因而造成账户白白丢失了500元。在Oracle数据库中,不会发生脏读的情况。

不可重复读(unrepeatable read)

不可重复读是指 A事务读取了B事务已经提交的更改数据。假设A在取款事务的过程中,B往该账户转账100元,A两次读取账户的余额发生不一致: 15150645_B8Se   在同一事务中,T4时间点和T7时间点读取账户存款余额不一样。

幻象读(phantom read)

A事务读取B事务提交的新增数据,这时A事务将出现幻象读的问题。幻象读一般发生在计算统计数据的事务中,举一个例子,假设银行系统在同一个事务中,两次统计存款账户的总金额,在两次统计过程中,刚好新增了一个存款账户,并存入100元,这时,两次统计的总金额将不一致: 15150645_d6yw   如果新增数据刚好满足事务的查询条件,这个新数据就进入了事务的视野,因而产生了两个统计不一致的情况。 幻象读和不可重复读是两个容易混淆的概念,前者是指读到了其他已经提交事务的新增数据,而后者是指读到了已经提交事务的更改数据(更改或删除),为了避免这两种情况,采取的对策是不同的,防止读取到更改数据,只需要对操作的数据添加行级锁,阻止操作中的数据发生变化,而防止读取到新增数据,则往往需要添加表级锁——将整个表锁定,防止新增数据(Oracle使用多版本数据的方式实现)。

第一类丢失更新

A事务撤销时,把已经提交的B事务的更新数据覆盖了。这种错误可能造成很严重的问题,通过下面的账户取款转账就可以看出来: 15150645_d6yw A事务在撤销时,“不小心”将B事务已经转入账户的金额给抹去了。

第二类丢失更新

A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失: 15150645_d6yw   上面的例子里由于支票转账事务覆盖了取款事务对存款余额所做的更新,导致银行最后损失了100元,相反如果转账事务先提交,那么用户账户将损失100元。

四种隔离级别

尽管数据库为用户提供了锁的DML操作方式,但直接使用锁管理是非常麻烦的,因此数据库为用户提供了自动锁机制。只要用户指定会话的事务隔离级别,数据库就会分析事务中的SQL语句,然后自动为事务操作的数据资源添加上适合的锁。此外数据库还会维护这些锁,当一个资源上的锁数目太多时,自动进行锁升级以提高系统的运行性能,而这一过程对用户来说完全是透明的。 ANSI/ISO SQL 92标准定义了4个等级的事务隔离级别: 15150645_d6yw   事务的隔离级别和数据库并发性是对立的,两者此增彼长。一般来说,使用READ UNCOMMITED隔离级别的数据库拥有最高的并发性和吞吐量,而使用SERIALIZABLE隔离级别的数据库并发性最低。 Mysql的默认隔离级别时Repeatable Read,即可重复读。

0%