作者归档:admin

那段不堪回首的日子

佛说:“人生有八苦,生,老,病,死,爱别离,怨憎会,求不得,五取蕴。”

病来如山倒,若那山倒没有致人命,则涌来一段如抽丝般的慢慢的折磨。

2012年8月24日,在经历了一天一晚的头痛后,早晨起来,发现无法实现吐口水等常规动作,半边脸已在受控范围之外。去医院,挂 神经科,得结果为面瘫,又名周围性面神经炎。医生开三天药,吃完复诊,没有好转,建议去康复科做针灸治疗。于是开始了两个多月的”抽丝过程“。最开始是消炎,早晨八点做针灸治疗(因为近视度数较高,无法做高压氧治疗),晚上吊水消炎。一个星期后头痛症状消失,停止吊水,开始每天早上请假治疗,白天上班的日子。在这些日子里,
体会了注射器在脸上扎针推药水过程中那种凉凉药水注射到脸上肌肉的感觉
体会了约十根针扎在脸上被脉动的电击振动的感觉
体会了长长的针从耳朵后面扎进去后做肌肉注射后对耳朵压迫的那种极度的胀痛
体会了在针灸时暖暖的红外线照在脸上让人可以小眯一会儿的舒服。
体会了慢慢可以控制自己脸上表情的惊喜
体会了失而复得的喜悦
体会了……

当然,也名正言顺可以不做表情,装酷,虽然不甚好看。
在用了兄弟在老家找到中药偏方以及坚持在医院治疗后,终于在十一前,可以在浅笑时不会很明显了,回家结婚也没有人看出来脸上有毛病。万幸!

现在就算大笑也没有问题了,只是还有部分肌肉无力,还在吃药,持续战斗中……

据说此病会复发
据说此病会有后遗症
据说有10%的人是冶不好的
据说……

之前一直有一句话在脑海中回响:”修身、齐家、冶国、平天下“。身体健康也应该是身修的一个很重要的部分。工作重要、学习重要、生活质量重要,这些能重要的一个大前提是身体健康,能有一个强健的体魄去实现你的工作计划、学习计划,能让你能舒服的享受生活。

文字很短、过程很长,道不出此中的滋味。只愿这世上的人们,少一些病痛,多一些健康、多一些幸福。

阿门!

锁机制之MySQL表锁

如何保证在被并发访问时数据的一致性、完整性和有效性,是数据库关注的核心问题。数据库的锁机制就是为了解决这个问题而出现的。锁机制在一定程度上将对共享资源的并发访问有序化,从而保证数据的一致完整性。锁机制的好坏直接影响到数据的并发处理能力和性能。一个好的锁机制的实现是一个数据的核心竞争力之一。

我们知道在MySQL中存在表级锁、页级锁和行级锁,其中MySQL默认实现了表级锁定。其它锁机制在不同的存储引擎中实现,这也是MySQL特点之一:针对特定的应用场景可以使用当前合适的存储引擎。先不论各种存储引擎和锁机制的优劣,这里只是说说他们各自的特点和实现。

MyISAM存储引擎作为曾经的默认存储引擎,其使用的锁机制是MySQL提供的默认表级锁定。虽然它没有实现自己的锁机制,但是在默认表级锁的基础上,增加了并发插入的特性。并发插入与系统参数concurrent_insert相关,concurrent_insert有三个值:

  • concurrent_insert=0 关闭并发写入
  • concurrent_insert=1 (默认)在没有空数据块的MyISAM表中启用并行插入
  • concurrent_insert=2 为所有MyISAM表启用并行插入。如果表有空记录或正被另一线程使用,新行将插入到表的最后。如果表未使用,MySQL将进行普通读锁定并将新行插入空记录。

此参数与MyISAM存储引擎的数据存储方式相关:常规情况下,MyISAM的新数据都会被附加到数据文件的结尾,当做了一些DELETE操作之后,数据文件就不再是连续的,形象一点来说,就是数据文件里出现了很多hole,此时再插入新数据时,按缺省设置会先看这些hole的大小是否可以容纳下新数据,如果可以,则直接把新数据保存到hole里,反之,则把新数据保存到数据文件的结尾。之所以这样做是为了减少数据文件的大小,降低文件碎片的产生。

如果我们使用concurrent_insert=2(通常也推荐这样做),这样会产生较多的文件碎片,为此,我们需要在设置这个参数值的同时,定期对数据表进行OPTIMIZE TABLE操作。此操作可以去除删除操作后留下的数据文件碎片,减小文件尺寸,加快未来的读写操作。但是,在OPTIMIZE TABLE运行过程中,MySQL会锁表。

MySQL的表锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)。共享锁和独占锁在锁机制中是一种非常普通的实现方式。 MyISAM在执行查询语句前,会自动给涉及的所有表加读锁,在执行更新操作(DDL)前,会自动给相关的表加写锁。 MySQL的读写锁(mysys/thr_lock.c)是通过4个队列来维护的,他们分别是:

  • 当前读锁队列(lock->read): 存储当前持有读锁所有线程相关信息,按获取锁的时间排序
  • 读锁等待队列(lock->read_wait):存储正在等待读锁锁定资源的线程相关信息
  • 当前写锁队列(lock->write):存储当前持有写锁所有线程相关信息,按获取锁的时间排序
  • 写锁等待队列(lock->write_wait):存储正在等待写锁锁定资源的线程相关信息

对于读锁,当请求的资源没有加写锁或在写锁等待队列中没有更高优先级的写锁定在等待。读锁是共享锁,不会阻塞其他进程对同一资源的读请求,但会阻塞对同一资源的写请求。只有当读锁释放后,才会执行其它进程的写操作。

对于写锁,当请求的资源在当前写锁队列、写锁等待队列或当前读锁队列,进入等待写锁队列;写锁会阻塞其他进程对同一资源的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。

表锁是MySQL数据库中加锁粒度最大的一种锁,除此之外,MySQL还有页级锁和行锁。表锁的执行开销小,加锁速度快,不会出现死锁,但是其加锁的粒度大,发生锁冲突的概率非常高,从而导致并发度低。可以考虑使用主从结构解决并发度低的问题。

参考资料

http://www.zhaokunyao.com/archives/206

http://dev.mysql.com/doc/refman/5.1/zh/database-administration.html

《MySQL性能调优与架构设计》 – 简朝阳

PHP内核中的异常基类

PHP内核中的异常基类

<<思考PHP语言三:异常处理>>中有说到异常的定义:异常处理是指在语言中能够使程序按照一种标准的方法对于某些运行时错误和其他程序所检测到的异常事件做出反应。异常发生的时间是不可以确定的,如果一种语言不包括异常处理机制,这就会给语言带来额外的复杂性。对于异常的处理有三种方案,而PHP5使用的是将一个异常处理独立出来,作为专门的子程序或类存在。

Exception是PHP中所有异常的基类,自从PHP5.1.0开始引入,自此,我们可以以面向对象的方式处理错误。 Exception类的声明如下:

 
 Exception {
        /* 属性 */
        protected string $message ;
        protected int $code ;
        protected string $file ;
        protected int $line ;
 
        /* 方法 */
        public __construct ([ string $message = "" [, int $code = 0 [, Exception $previous = NULL ]]] )
        final public string getMessage ( void )
        final public Exception getPrevious ( void )
        final public int getCode ( void )
        final public string getFile ( void )
        final public int getLine ( void )
        final public array getTrace ( void )
        final public string getTraceAsString ( void )
        public string __toString ( void )
        final private void __clone ( void )
    }

其中message表示异常消息内容,code表示异常代码,file表示抛出异常的文件名,line表示抛出异常在该文件中的行号。下面从 PHP内核的角度说明这些属性及对应的方法。

message表示异常的消息内容,其对应getMessage方法。message是自定义的异常消息,默认为空字符串。对于PHP内核来说,创建Exception对象时,有无message参数会影响 getMessage方法的返回值,以及显示异常时是否有with message %s等字样。message成员变量的作用是为了让用户更好的定义说明异常类。

code表示异常代码,其对应getCode方法。和meesage成员变量一样,code也是用户自定义的内容,默认为0。

file表示抛出异常的文件名,其对应getFile方法,返回值为执行文件的文件名,在PHP内核中存储此文件名的字段为 EG(active_op_array)->filename 此字段的值在生成一个opcode列表时,PHP的内核会将此前正在编译文件的文件名赋值给opcode的filename属性,如生成一个函数的op_array,在初始化op_array时,会执行上面所说的赋值操作,这里的赋值是通过编译的全局变量来传递的。当代码执行时,EG(active_op_array)表示正在执行的opcode列表。

line表示抛出异常在该文件中的行号,其对应getLine方法,返回整数,即EG(opline_ptr)->lineno。对于每条PHP脚本生成的opcode,在编译时都会执行一次初始化操作,在这次初始化操作中,PHP内核会将当前正在编译的行号赋值给opcode的lineno属性。 EG(opline_ptr)是PHP内核执行的当前opcode,抛出异常时对应的行号即为此对象的lineno属性。

除了上面四个属性,异常类还包括一个非常重要的内容:异常的追踪信息。在异常类中,通过getTrace方法可以获取这些信息。此方法的作用相当于PHP的内置函数debug_backtrace。在代码实现层面他们最终都是调用zend_fetch_debug_backtrace函数。在此函数中通过回溯PHP的调用栈,返回代码追踪信息。与getTrace方法对应还有一个返回被串化值的方法getTraceAsString,以字符串替代数组返回异常追踪信息。

在构造函数中,从PHP5.3.0增加$previous参数,表示异常链中的前一个异常。在catch块中可以抛出一个新的异常,并引用原始的异常,为调试提供更多的信息。