CodeIgniter框架数据库事务处理的设计缺陷和解决方案
起因:
在我们线上的某个业务中,使用较老版本的CodeIgniter框架,其中的DB类中,对DB事物处理部分存在着一个设计上的缺陷,或许也算不上缺陷吧。但他却影响了我们生产环境,导致连锁反应。对业务产生较大影响,且不容易排查。这个问题,我在今年的3月中旬,曾向codeigniter中国的站长Hex报告过,之后,我也忘记这件事情了。直到今天,我们线上业务又一次以为这个问题,害的我又排查一次。具体原因,各位且先听我慢慢说完。(这个问题同样存在于最新版本Version2.1.0中)
分析:
以CodeIgniter框架Version2.1.0为例,在system\database\DB_driver.php的CI_DB_driver类中第58行有个$_trans_status属性。
//system\database\DB_driver.php var$trans_strict =TRUE; var$_trans_depth =0; var$_trans_status =TRUE;//Usedwithtransactionstodetermineifarollbackshouldoccur var$cache_on =FALSE;
同时,这个类的query方法中,有赋值此属性的代码,见文件306、307行
//Thiswilltriggerarollbackiftransactionsarebeingused $this->_trans_status=FALSE;
这里也给了注释,告诉我们,如果使用了事物处理,那么这属性将成为一个回滚的决定条件。
在520行的事物提交方法trans_complete中,如下代码:
/** *CompleteTransaction * *@access public *@return bool */ functiontrans_complete() { if(!$this->trans_enabled) { returnFALSE; }
//Whentransactionsarenestedweonlybegin/commit/rollbacktheoutermostones if($this->_trans_depth>1) { $this->_trans_depth-=1; returnTRUE; }
//Thequery()functionwillsetthisflagtoFALSEintheeventthataqueryfailed if($this->_trans_status===FALSE) { $this->trans_rollback();
//IfweareNOTrunninginstrictmode,wewillreset //the_trans_statusflagsothatsubsequentgroupsoftransactions //willbepermitted. if($this->trans_strict===FALSE) { $this->_trans_status=TRUE; }
log_message('debug','DBTransactionFailure'); returnFALSE; }
$this->trans_commit(); returnTRUE; }