转自 http://blog.csdn.net/mengxiangbaidu/article/details/7029694
虽然我们可以使用CActvieReord完成大部分对数据库的操作。他简化了数据库操作,但是有时候却把一些数据库操作复杂化了。所以YII同时允许我们可以自己连接数据库,组织查询语句,执行查询语句,获取查询结果。这样可以让我们灵活的选择使用哪一种方式。
下面讲讲YII提供的DAO操作相关类的使用方法。具体类在framework/db文件夹中
- .
- ├── ar
- │ ├── CActiveFinder.php
- │ ├── CActiveRecordBehavior.php
- │ └── CActiveRecord.php
- ├── CDbCommand.php主要用于执行数据库相关操作的sql语句
- ├── CDbConnection.php用于连接数据库
- ├── CDbDataReader.php对数据库结果集操作
- ├── CDbException.php数据库异常类
- ├── CDbMigration.php数据库迁移
- ├── CDbTransaction.php数据库事务
- └── schema底层的数据库操作语法,针对不同的数据库,如果你想自定义其他数据库操作,可以在这里参考yii提供的数据库操作的类实现。
- ├── CDbColumnSchema.php
- ├── CDbCommandBuilder.php
- ├── CDbCriteria.php
- ├── CDbExpression.php
- ├── CDbSchema.php
- ├── CDbTableSchema.php
- ├── mssql
- │ ├── CMssqlColumnSchema.php
- │ ├── CMssqlCommandBuilder.php
- │ ├── CMssqlPdoAdapter.php
- │ ├── CMssqlSchema.php
- │ └── CMssqlTableSchema.php
- ├── mysql
- │ ├── CMysqlColumnSchema.php
- │ ├── CMysqlSchema.php
- │ └── CMysqlTableSchema.php
- ├── oci
- │ ├── COciColumnSchema.php
- │ ├── COciCommandBuilder.php
- │ ├── COciSchema.php
- │ └── COciTableSchema.php
- ├── pgsql
- │ ├── CPgsqlColumnSchema.php
- │ ├── CPgsqlSchema.php
- │ └── CPgsqlTableSchema.php
- └── sqlite
- ├── CSqliteColumnSchema.php
- ├── CSqliteCommandBuilder.php
- └── CSqliteSchema.php
- 7 directories, 33 files
可以看到,数据库操作类主要是:
├── CDbConnection.php
├── CDbCommand.php
├── CDbDataReader.php
├── CDbException.php
├── CDbMigration.php
├── CDbTransaction.php
连接,执行,结果集操作,事物,异常,数据迁移。
1.数据库连接 CDbConnection.php
YII中的DAO是封装的PDO,那么连接数据库要提供的必要信息(连接方式,用户名,密码)自然也类似。打开类看看具体实现方式和使用方法。
通过类的注释可以了解连接方法。
- * CDbConnection represents a connection to a database.
- *
- * CDbConnection works together with {@link CDbCommand}, {@link CDbDataReader}
- * and {@link CDbTransaction} to provide data access to various DBMS
- * in a common set of APIs. They are a thin wrapper of the {@link http://www.php.net/manual/en/ref.pdo.php PDO}
- * PHP extension.
- *
- * To establish a connection, set {@link setActive active} to true after
- * specifying {@link connectionString}, {@link username} and {@link password}.
- *
- * The following example shows how to create a CDbConnection instance and establish
- * the actual connection:
- * <pre>
- * $connection=new CDbConnection($dsn,$username,$password);
- * $connection->active=true;
- * </pre>
参数:
$dsn:
- /**
- * @var string The Data Source Name, or DSN, contains the information required to connect to the database.
- * @see http://www.php.net/manual/en/function.PDO-construct.php
- *
- * Note that if you're using GBK or BIG5 then it's highly recommended to
- * update to PHP 5.3.6+ and to specify charset via DSN like
- * 'mysql:dbname=mydatabase;host=127.0.0.1;charset=GBK;'.
- */
- public $connectionString;
http://www.php.net/manual/en/function.PDO-construct.php。
http://cn2.php.net/manual/en/pdo.drivers.php
格式如下:
uri:file:///path/to/dsnfile
YII官方给出的常见的DSN格式如下:
- SQLite:
sqlite:/path/to/dbfile
- MySQL:
mysql:host=localhost;dbname=testdb
- PostgreSQL:
pgsql:host=localhost;port=5432;dbname=testdb
- SQL Server:
mssql:host=localhost;dbname=testdb
- Oracle:
oci:dbname=//localhost:1521/testdb
$username
$password
具体举例如下:
/yii_dev/testwebap/protected/models/Member.php
- <?php
- class Member extends CModel
- {
- private $connection = null;
- public function __construct ()
- {
- //YII的强大,让你可以直接用下面的语句连接,更简单
- $this->connection = Yii::app()->db;
- //or,下面也可以,就是蛮笨的,当然也是基本的
- /*
- $dsn = Yii::app()->db->connectionString;
- $username = Yii::app()->db->username;
- $password = Yii::app()->db->password;
- $this->connection = new CDbConnection($dsn, $username, $password);
- $this->connection->charset = 'utf8';
- $this->connection->active = true;
- */
- }
- /**
- * Returns the static model of the specified AR class.
- * @return User the static model class
- */
- public static function model ($className = __CLASS__)
- {
- return parent::model($className);
- }
- /**
- *
- * 连接状态
- */
- public function stats ()
- {
- return $this->connection ? 'connection successful!' : 'connection fail!';
- }
- public function attributeNames ()
- {}
- }
$this->connection->active = true;表示打开连接。
/yii_dev/testwebap/protected/modules/testmod/controllers/DefaultController.php
- <?php
- class DefaultController extends Controller
- {
- public function actionDao ()
- {
- $memberModel = new Member();
- var_dump($memberModel->stats());
- }
具体的实现方式,可以自行参考类,这里不再累述。
2.数据库基本操作CDbCommand.php
数据库连接建立后,便可以通过CDbCommand类提供的方法就可以进行数据库操作。
类给出的使用方法:
- * After the DB connection is established, one can execute an SQL statement like the following:
- * <pre>
- * $command=$connection->createCommand($sqlStatement);
- * $command->execute(); // a non-query SQL statement execution
- * // or execute an SQL query and fetch the result set
- * $reader=$command->query();
- *
- * // each $row is an array representing a row of data
- * foreach($reader as $row) ...
- * </pre>
- *
- * One can do prepared SQL execution and bind parameters to the prepared SQL:
- * <pre>
- * $command=$connection->createCommand($sqlStatement);
- * $command->bindParam($name1,$value1);
- * $command->bindParam($name2,$value2);
- * $command->execute();
- * </pre>
基本使用方法如下
- <?php
- class Member extends CModel
- {
- private $connection = null;
- private $command = null;
- public function __construct ()
- {
- $this->connection = Yii::app()->db;
- }
- /**
- * Returns the static model of the specified AR class.
- * @return User the static model class
- */
- public static function model ($className = __CLASS__)
- {
- return parent::model($className);
- }
- /**
- *
- * 连接状态
- */
- public function stats ()
- {
- return $this->connection ? 'connection successful!' : 'connection fail!';
- }
- /**
- *
- * 获取所有用户名
- */
- public function getUsernames ()
- {
- $sqlStatement = ' SELECT `username` FROM `testdrive`.`tbl_user` ';
- $this->command = $this->connection->createCommand($sqlStatement);
- return $this->command->queryAll();
- }
- /**
- *
- * 获取指定用户的昵称
- * @param string $userName
- */
- public function getNickname ($userName)
- {
- $sqlStatement = ' SELECT `username` FROM `testdrive`.`tbl_user` WHERE `username`=:username ';
- $this->command = $this->connection->createCommand($sqlStatement);
- $this->command->bindParam('username', $userName);
- return $this->command->queryAll();
- }
- /**
- *
- * 添加一个用户
- */
- public function addUser ()
- {
- $sqlStatement = " INSERT INTO `tbl_user` (`username`, `password`, `email`) VALUES ('test', 'test', 'test@test.com') ";
- $this->command = $this->connection->createCommand($sqlStatement);
- return $this->command->execute();
- }
- public function attributeNames ()
- {}
- }
- <?php
- class DefaultController extends Controller
- {
- public function actionUsernames ()
- {
- $memberModel = new Member();
- var_dump($memberModel->getUsernames());
- }
- public function actionNickname ()
- {
- $memberModel = new Member();
- var_dump($memberModel->getNickname('admin'));
- }
- public function actionAdduser ()
- {
- $memberModel = new Member();
- var_dump($memberModel->addUser());
- }
总结:
*****常用函数
(1)如果你执行的SQL语句有返回结果集: 例如SELECT。通常用query开头的系列函数:
常见的有:
$dataReader=$command->query(); // 执行一个 SQL 查询 $rows=$command->queryAll(); // 查询并返回结果中的所有行 $row=$command->queryRow(); // 查询并返回结果中的第一行 $column=$command->queryColumn(); // 查询并返回结果中的第一列 $value=$command->queryScalar(); // 查询并返回结果中第一行的第一个字段query()方法执行如果成功,它将返回一个CDbDataReader 实例,通过此实例可以遍历数据的结果行。
为简便起见, (Yii)还实现了一系列queryXXX()
方法以直接返回查询结果。
(2)你执行的SQL语句返回的不是结果集,只是状态值,例如:INSERT ,UPDATE,DELETE.则用execute()
例如
$this->command->execute();
*****结果集操作类CDbDataReader的使用方法有两种方法,参见如下代码
- /**
- *
- * 获取所有用户名
- */
- public function getUsernames ()
- {
- $sqlStatement = ' SELECT `username` FROM `testdrive`.`tbl_user` ';
- $this->command = $this->connection->createCommand($sqlStatement);
- $dataReader = $this->command->query();
- // 重复调用 read() 直到它返回 false
- while (($row = $dataReader->read()) !== false) {
- var_dump($row);
- }
- foreach ($dataReader as $row) {
- var_dump($row);
- }
- }
CDbDataReader还提供了其他的方法。例如获取行数,将所有数据转存储到一个数组等等,具体的可参考类的代码。
*****表前缀
从版本 1.1.0 起, Yii 提供了集成了对使用表前缀的支持。 表前缀是指在当前连接的数据库中的数据表的名字前面添加的一个字符串。 它常用于共享的服务器环境,这种环境中多个应用可能会共享同一个数据库,要使用不同的表前缀以相互区分。 例如,一个应用可以使用 tbl_
作为表前缀而另一个可以使用 yii_
。
要使用表前缀,配置 CDbConnection::tablePrefix 属性为所希望的表前缀。 然后,在 SQL 语句中使用{{TableName}}
代表表的名字,其中的 TableName
是指不带前缀的表名。 例如,如果数据库含有一个名为tbl_user
的表,而 tbl_
被配置为表前缀,那我们就可以使用如下代码执行用户相关的查询:
$sql='SELECT * FROM {{user}}'; $users=$connection->createCommand($sql)->queryAll();
*****绑定参数
要避免 SQL 注入攻击 并提高重复执行的 SQL 语句的效率, 你可以 "准备(prepare)"一条含有可选参数占位符的 SQL 语句,在参数绑定时,这些占位符将被替换为实际的参数。
参数占位符可以是命名的 (表现为一个唯一的标记) 或未命名的 (表现为一个问号)。调用CDbCommand::bindParam() 或 CDbCommand::bindValue() 以使用实际参数替换这些占位符。 这些参数不需要使用引号引起来:底层的数据库驱动会为你搞定这个。 参数绑定必须在 SQL 语句执行之前完成。
// 一条带有两个占位符 ":username" 和 ":email"的 SQL $sql="INSERT INTO tbl_user (username, email) VALUES(:username,:email)"; $command=$connection->createCommand($sql); // 用实际的用户名替换占位符 ":username" $command->bindParam(":username",$username,PDO::PARAM_STR); // 用实际的 Email 替换占位符 ":email" $command->bindParam(":email",$email,PDO::PARAM_STR); $command->execute(); // 使用新的参数集插入另一行 $command->bindParam(":username",$username2,PDO::PARAM_STR); $command->bindParam(":email",$email2,PDO::PARAM_STR); $command->execute();
方法 bindParam() 和 bindValue() 非常相似。唯一的区别就是前者使用一个 PHP 变量绑定参数, 而后者使用一个值。对于那些内存中的大数据块参数,处于性能的考虑,应优先使用前者。
关于绑定参数的更多信息,请参考 相关的PHP文档。
*****绑定列
当获取查询结果时,你也可以使用 PHP 变量绑定列。 这样在每次获取查询结果中的一行时就会自动使用最新的值填充。
$sql="SELECT username, email FROM tbl_user"; $dataReader=$connection->createCommand($sql)->query(); // 使用 $username 变量绑定第一列 (username) $dataReader->bindColumn(1,$username); // 使用 $email 变量绑定第二列 (email) $dataReader->bindColumn(2,$email); while($dataReader->read()!==false) { // $username 和 $email 含有当前行中的 username 和 email }
详细的使用方法参考官方的《Query Builder》,下一节将会对其做翻译
3.数据库事务操作CDbTransaction.php
当一个应用要执行几条查询,每条查询要从数据库中读取并/或向数据库中写入信息时, 保证数据库没有留下几条查询而只执行了另外几条查询是非常重要的。 事务,在 Yii 中表现为 CDbTransaction 实例,可能会在下面的情况中启动:
- 开始事务.
- 一个个执行查询。任何对数据库的更新对外界不可见。
- 提交事务。如果事务成功,更新变为可见。
- 如果查询中的一个失败,整个事务回滚。
上述工作流可以通过如下代码实现:
$transaction=$connection->beginTransaction(); try { $connection->createCommand($sql1)->execute(); $connection->createCommand($sql2)->execute(); //.... other SQL executions $transaction->commit(); } catch(Exception $e) // 如果有一条查询失败,则会抛出异常 { $transaction->rollBack(); }
4.数据库操作异常类CDbException