This article is the second in a series of YII learning summary articles. It mainly introduces us to the Data Access Object (DAO). It is very detailed. Please refer to it if you need it.
Yii provides powerful database programming support. Yii Data Access Object (DAO) is built on the PHP Data Object (PDO) extension, enabling access to different database management systems (DBMS) through a single unified interface. Applications developed using Yii's DAO can easily switch to use different database management systems without modifying the data access code.
Data Access Object (DAO) provides a common API for accessing data stored in different database management systems (DBMS). Therefore, when changing the underlying DBMS to another, there is no need to modify the code that uses DAO to access data.
Yii DAO is built on PHP Data Objects (PDO). It is an extension that provides unified data access for many popular DBMS, including MySQL, PostgreSQL, etc. Therefore, to use Yii DAO, the PDO extension and specific PDO database driver (such as PDO_MYSQL) must be installed.
Yii DAO mainly includes the following four classes:
CDbConnection: represents a database connection.
CDbCommand: Represents a SQL statement executed through the database.
CDbDataReader: Represents a forward-only stream of rows from a query result set.
CDbTransaction: Represents a database transaction.
Below, we introduce the application of Yii DAO in different scenarios.
1. Establish a database connection
To establish a database connection, create a CDbConnection instance and activate it. Connecting to a database requires a data source name (DSN) to specify connection information. Username and password may also be used. When an error occurs while connecting to the database (for example, wrong DSN or invalid username/password), an exception will be thrown.
The code is as follows:
$connection=new CDbConnection($dsn,$username,$password); // 建立连接。你可以使用 try...catch 捕获可能抛出的异常 $connection->active=true; ...... $connection->active=false; // 关闭连接
The format of DSN depends on the PDO database driver used. In general, the DSN contains the name of the PDO driver, followed by a colon, followed by driver-specific connection syntax. Check out the PDO documentation for more information. Below is a list of commonly used DSN formats.
The code is as follows:
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
Since CDbConnection inherits from CApplicationComponent, we can also use it as an application component. To do this, please configure a db (or other name) application component in the application configuration as follows:
The code is as follows:
array( ...... 'components'=>array( ...... 'db'=>array( 'class'=>'CDbConnection', 'connectionString'=>'mysql:host=localhost;dbname=testdb', 'username'=>'root', 'password'=>'password', 'emulatePrepare'=>true, // needed by some MySQL installations ), ), )
Then we can access the database through Yii::app()->db Connected. It is automatically activated unless we specifically configure CDbConnection::autoConnect to false. This way, this single DB connection can be shared in many places in our code.
2. Execute SQL statement
After the database connection is established, the SQL statement can be executed by using CDbCommand. You can create a CDbCommand instance by calling CDbConnection::createCommand() with the specified SQL statement as argument.
The code is as follows:
$connection=Yii::app()->db; // 假设你已经建立了一个 "db" 连接 // 如果没有,你可能需要显式建立一个连接: // $connection=new CDbConnection($dsn,$username,$password); $command=$connection->createCommand($sql); // 如果需要,此 SQL 语句可通过如下方式修改: // $command->text=$newSQL;
A SQL statement will be executed through CDbCommand in the following two ways:
execute(): Execute a non-query SQL statement, such as INSERT, UPDATE and DELETE. If successful, it returns the number of rows affected by this execution.
query(): Execute a SQL statement that returns several rows of data, such as SELECT. If successful, it returns a CDbDataReader instance through which the resulting rows of data can be iterated. For simplicity, (Yii) also implements a series of queryXXX() methods to directly return query results.
If an error occurs when executing a SQL statement, an exception will be thrown.
The code is as follows:
$rowCount=$command->execute(); // 执行无查询 SQL $dataReader=$command->query(); // 执行一个 SQL 查询 $rows=$command->queryAll(); // 查询并返回结果中的所有行 $row=$command->queryRow(); // 查询并返回结果中的第一行 $column=$command->queryColumn(); // 查询并返回结果中的第一列 $value=$command->queryScalar(); // 查询并返回结果中第一行的第一个字段
3. Get query results
After CDbCommand::query() generates a CDbDataReader instance, you can get the rows in the result by repeatedly calling CDbDataReader::read(). You can also use CDbDataReader in PHP's foreach language construct to retrieve data row by row.
The code is as follows:
$dataReader=$command->query(); // 重复调用 read() 直到它返回 false while(($row=$dataReader->read())!==false) { ... } // 使用 foreach 遍历数据中的每一行 foreach($dataReader as $row) { ... } // 一次性提取所有行到一个数组 $rows=$dataReader->readAll();
Note: Unlike query(), all queryXXX() methods will return data directly. For example, queryRow() returns an array representing the first row of the query results.
4. Use transactions
When an application needs to execute several queries, and each query needs to read from the database and/or write information to the database, ensure that the database does not leave several queries and only executes others. The query is very important. Transactions, represented in Yii as CDbTransaction instances, may be started in the following situations:
Start transaction.
Execute queries one by one. Any updates to the database are not visible to the outside world.
Submit the transaction. If the transaction succeeds, the update becomes visible.
If one of the queries fails, the entire transaction is rolled back.
The above workflow can be realized through the following code:
The code is as follows:
$transaction=$connection->beginTransaction(); try { $connection->createCommand($sql1)->execute(); $connection->createCommand($sql2)->execute(); //.... other SQL executions $transaction->commit(); } catch(Exception $e) // 如果有一条查询失败,则会抛出异常 { $transaction->rollBack(); }
5. 绑定参数
要避免 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文档。
6. 绑定列
当获取查询结果时,你也可以使用 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 }
7. 使用表前缀
从版本 1.1.0 起, Yii 提供了集成了对使用表前缀的支持。 表前缀是指在当前连接的数据库中的数据表的名字前面添加的一个字符串。 它常用于共享的服务器环境,这种环境中多个应用可能会共享同一个数据库,要使用不同的表前缀以相互区分。 例如,一个应用可以使用 tbl_ 作为表前缀而另一个可以使用 yii_。
要使用表前缀,配置 CDbConnection::tablePrefix 属性为所希望的表前缀。 然后,在 SQL 语句中使用{{TableName}} 代表表的名字,其中的 TableName 是指不带前缀的表名。 例如,如果数据库含有一个名为tbl_user 的表,而 tbl_ 被配置为表前缀,那我们就可以使用如下代码执行用户相关的查询:
代码如下:
$sql='SELECT * FROM {{user}}'; $users=$connection->createCommand($sql)->queryAll();