?
数据库类几乎是每个PHP框架必不可少的组件之一,Yii的数据库核心主要包含两类,一类是管理数据库连接的CDbConnection及相关类,另一类是ORM(Object Relation Model),即管理数据库表记录的CActiveRecord及相关类。
首先我将介绍和分析数据库连接管理类CDbConnection,CDbConnect作为CApplication的核心组件,在应用初始化时会自动进行初始化,对于使用者来说,需要在配置文件中将配置CDbConnection的初始化配置:
?
//protected/config/main.php: 'components'=>array( …… 'db'=>array( //连接字符串,设置数据库类型,数据库主机地址,数据库名 'connectionString' => 'mysql:host=localhost;dbname=blog', //用户名 'username' => 'root', //密码 'password' => '123456', //字符集 'charset' => 'utf8', ), ……
?
?在应用初始化时,会自动初始化CDbConnectiont:
?
//CApplication: abstract class CApplication extends CModule //构造函数 public function __construct($config=null) { …… //注册核心组件 $this->registerCoreComponents(); …… } …… protected function registerCoreComponents() { //核心组件列表 $components=array( …… 'db'=>array( 'class'=>'CDbConnection', ), …… }; //调用父类函数注册 $this->setComponents($components); } //CModule: abstract class CModule extends CComponent public function setComponents($components,$merge=true) { foreach($components as $id=>$component) { //如果是接口IApplicationComponent的一个实例 //调用setComponent //CDbConnect继承自CApplicationComponent //CApplicationCompnent继承了IApplicationCompnent接口 if($component instanceof IApplicationComponent) $this->setComponent($id,$component); else if(isset($this->_componentConfig[$id]) && $merge) $this->_componentConfig[$id]=CMap::mergeArray($this->_componentConfig[$id],$component); else $this->_componentConfig[$id]=$component; } } public function setComponent($id,$component) { if($component===null) unset($this->_components[$id]); else { $this->_components[$id]=$component; //初始化组件 if(!$component->getIsInitialized()) $component->init(); } } }
?
?
接下来我们看看CDbConnect在初始化阶段,都做了那些事情:
?
/** * CDbConnection与CDbCommand、CDbDataReader和CDbTransaction一起合作提供对DBMS的数据访问功能 * 它使用PDO作为数据库连接驱动 */ class CDbConnection extends CApplicationComponent { //以下属性在配置文件中设置 public $connectionString; public $username=''; public $password=''; public $charset; //表结构缓存时间,单位是秒,默认不缓存 public $schemaCachingDuration=0; //表结构缓存排除列表 public $schemaCachingExclude=array(); //表结构缓存ID public $schemaCacheID='cache'; //自动连接,默认为true,如果设置为false,在使用时才会连接 public $autoConnect=true; //模仿prepare,默认为false,PDO会使用原生的prepare,对于某些数据库(例如MySql),最好设置为true,这样就不会使用有bug的PDO原生prepare,关于PDO的prepare相关信息可以查阅:http://php.net/manual/en/pdo.prepare.php public $emulatePrepare=false; //是否记录绑定变量(如果使用prepare方式进行查询,如果记录sql语句,是看不到绑定变量的值的),调试时使用 public $enableParamLogging=false; //是否记录SQL语句,调试时使用 public $enableProfiling=false; //数据表前缀 public $tablePrefix; //在建立数据库连接之后立即执行的SQL语句 public $initSQLs; //目前支持的数据库驱动 public $driverMap=array( 'pgsql'=>'CPgsqlSchema', // PostgreSQL 'mysqli'=>'CMysqlSchema', // MySQL 'mysql'=>'CMysqlSchema', // MySQL 'sqlite'=>'CSqliteSchema', // sqlite 3 'sqlite2'=>'CSqliteSchema', // sqlite 2 'mssql'=>'CMssqlSchema', // Mssql driver on windows hosts 'dblib'=>'CMssqlSchema', // dblib drivers on linux (and maybe others os) hosts 'sqlsrv'=>'CMssqlSchema', // Mssql 'oci'=>'COciSchema', // Oracle driver ); …… //初始化 public function init() { //调用父类初始化 parent::init(); // if($this->autoConnect) $this->setActive(true); } …… public function setActive($value) { //如果需要设置的状态与当前状态不同 if($value!=$this->_active) { if($value) $this->open(); else $this->close(); } } protected function open() { if($this->_pdo===null) { if(empty($this->connectionString)) throw new CDbException(Yii::t('yii','CDbConnection.connectionString cannot be empty.')); try { Yii::trace('Opening DB connection','system.db.CDbConnection'); //创建PDO实例 $this->_pdo=$this->createPdoInstance(); //初始化连接 $this->initConnection($this->_pdo); $this->_active=true; } catch(PDOException $e) { //异常处理 …… } } } …… //创建PDO实例 protected function createPdoInstance() { $pdoClass='PDO'; if(($pos=strpos($this->connectionString,':'))!==false) { $driver=strtolower(substr($this->connectionString,0,$pos)); if($driver==='mssql' || $driver==='dblib') $pdoClass='CMssqlPdoAdapter'; } return new $pdoClass($this->connectionString,$this->username, $this->password,$this->_attributes); } …… //初始化连接 protected function initConnection($pdo) { $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); if($this->emulatePrepare && constant('PDO::ATTR_EMULATE_PREPARES')) $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,true); if($this->charset!==null) { $driver=strtolower($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)); //pg,mysql,mysqli需要设置字符编码 if(in_array($driver,array('pgsql','mysql','mysqli'))) $pdo->exec('SET NAMES '.$pdo->quote($this->charset)); } //如果有初始化SQL,则执行 if($this->initSQLs!==null) { foreach($this->initSQLs as $sql) $pdo->exec($sql); } } }?
?
?
以上便是CDbConnect初始化的过程,其实CDnConnection主要功能是为用户封装了PDO的实例,并且自定义了一些配置,方便用户使用。
?
如果我们在项目中不想使用应用核心组件数据库连接,想自定义一个数据库连接,那么可以直接创建CDbConnection的对象:
$connection=new CDbConnection($dsn,$username,$password); //CDbConnection的祖先类Ccomponent包含有__isset方法,自动会调用名称为set[attribute]的方法,即会调用CdbConnection::setActive方法 $connection->active=true;? 如果想直接执行一条SQL:
$command=$connection->createCommand($sqlStatement); $command->execute(); // // 执行SQL获取结果 $reader=$command->query(); //$row代表一条记录 foreach($reader as $row) ...与CDbConnection密切相关的几个类有:
?