您的位置:首页 > 博客中心 > 数据库 >

YII 数据库相关操作

时间:2022-03-14 07:44

CDbConnection: 一个抽象数据库连接
CDbCommand: SQL statement
CDbDataReader: 匹配结果集的一行记录
CDbTransaction:数据库事务

访问数据库前需要建立数据库连接;使用DAO建立一个抽象数据库链接

1 $connection = new CDbConnection($dsn, $username, $password);
2 $connection->active = true;   // 只有激活了连接才可以使用
3 $connection->active = false;  // 关闭连接

CDbConnection继承自CApplicationComponent,所以他可以像组件一样在任何地方使用。因此可以这样访问

Yii::app()->db

执行SQL语句需要CDbCommand对象,而该对象由CdbConnection::createCommand()返回,因此

$connection=Yii::app()->db;
$command=$connection->createCommand($sql);

如果SQL语句想要完全由自己写,可以这样

$newSQL = ‘SQL语句‘;
$command->text=$newSQL;

CDbCommand对象有两个方法execute()用于非查询SQL执行,而query(),通俗的讲就是用于SELECT查询
execute()返回的是INSERT, UPDATE and DELETE操作受影响的记录行数
query()返回一个CDbDataReader对象,使用CDbDataReader对象可以遍历匹配结果集中的所有记录

$rowCount=$command->execute();  // execute the non-query SQL
$dataReader=$command->query();  // execute a query SQL // 返回CDbDataReader对像
$rows=$command->queryAll();     // query and return all rows of result
$row=$command->queryRow();      // query and return the first row of result
$column=$command->queryColumn();    // query and return the first column of result
$value=$command->queryScalar();     // query and return the first field in the first row

query()返回的是代表结果集的对象而非直接的结果,因此要获取结果集的记录可以这样

$dataReader=$command->query();
// CDbDataReader::read()可以一次获取一行数据,到末尾时返回false while(($row=$dataReader->read())!==false) {...}
// CDbDataReader实现了迭代器接口因此可以使用foreach遍历 foreach($dataReader as $row) {...}
// 一次性返回所有的记录(数组) $rows=$dataReader->readAll();

queryXXX() 形式的方法会直接返回匹配的记录集合,当query()不是,他返回一个代表结果集的对象

YII中的CDbTransaction类用于事务

// 首先,建立一个连接
$connection = Yii::app()->db;
// 第二,开始事务
$transaction=$connection->beginTransaction();
// 第三,执行SQL,如果错误就抛出异常,在异常处理中回滚。
try
{
    $connection->createCommand($sql1)->execute();
    $connection->createCommand($sql2)->execute();
    //.... other SQL executions
    // 如果SQL执行都没有抛出异常,那就提交。
    $transaction->commit(); 
} catch(Exception $e) {
    $transaction->rollBack();   // 在异常处理中回滚
}

执行SQL中,一般都需要绑定一些用户参数,对于用户参数,需要防止SQL注入攻击
PDO对象的绑定参数的方法可以防止SQL注入攻击,同样扩展自PDO的DAO也有这样的功能
举例说明:

// 第一,建立一个连接:
$connection = Yii::app()->db;
// 第二,写下无敌的SQL语句,比如:
$sql="INSERT INTO tbl_user (username, email) VALUES(:username,:email)";
// 第三,创建CDbCommand对象用于执行SQL
$command=$connection->createCommand($sql);
// 接下来,将SQL语句中的形式参数,替换为实际参数
$command->bindParam(":username",$username,PDO::PARAM STR);   // 这与PDO有点不同,PDO中不带冒号
$command->bindParam(":email",$email,PDO::PARAM STR);    // 同样
// 最后,执行
$command->execute();
// 如果还有其他的数据需要插入,可以再次绑定实参。

使用CDbDataReader对象的bindColumn()方法将结果集中的列绑定到PHP变量。
因此,读取一行记录,列值将自动填充到对应的PHP对象中
比如这样:

$connection = Yii::app()->db;
$sql = "SELECT username, email FROM tbl_user";
$dataReader = $connection->createCommand($sql)->query();    //很赞的方法链, 可惜不能接着.each()
$dataReader->bindColumn(1, $username);  //第一列值绑定到$username
$dataReader->bindColumn(2, $email);     //第二列值绑定到$email
//接着循环读取并操作数据
while( $dataReader->read() !== false ) {
    ... // 与先前的 while(($row=$dataReader->read())!==false) 有所不同哦!
}

设置表前缀,使用 CDbConnection::tablePrefix 属性在配置文件中设置

// Yii实现了把一条完整的SQL语句完完全全肢解的能力,比如这样:
$user = Yii::app()->db->createCommand();    
        ->select(‘id, username, profile‘)
        ->from(‘tbl_user u‘)
        ->join(‘tbl_profile p‘, ‘u.id=p.user_id‘)
        ->where(‘id=:id‘, array(‘:id‘=>$id)
        ->queryRow(); //返回匹配的结果集的第一行

其实这条语句是这样的: $newSQL =‘SELECT id, username, profile from tbl_user u INNER JOIN tbl_profile p ON u.id = p.user_id WHERE u.id =:id‘

yii提供了一种构建SQL的机制(也就是说不用自己写长长的SQL)
首相要实例化一个CDbCommand对象

$command = Yii::app()->db->createCommand(); // 注意参数留空了。。

可用的方法列表如下:

->select(): SELECT子句
->selectDistinct(): SELECT子句,并保持了记录的唯一性
->from():         构建FROM子句
->where():        构建WHERE子句
->join():         在FROM子句中构建INNER JOIN 子句
->leftJoin():     在FROM子句中构建左连接子句
->rightJoin():    在FROM子句中构建右连接子句
->crossJoin():    添加交叉查询片段(没用过)
->naturalJoin():  添加一个自然连接子片段
->group():        GROUP BY子句
->having():       类似于WHERE的子句,但要与GROUP BY连用
->order():        ORDER BY子句
->limit():        LIMIT子句的第一部分
->offset():       LIMIT子句的第二部分
->union():        appends a UNION query fragment

select()默认返回全部列

// 但你可以这样:
select(‘username, email‘);
// 或使用表限定,或使用别名
select(‘tbl_user.id, username name‘);
// 或使用数组作为参数
select(array(‘id‘, ‘count(*) as num‘));

from() 如果制定了多个表需要使用逗号分隔的字符串,就像原生SQL语句那样:

from(‘tbl_user, tbl_post, tbl_profile‘);
// 当然,你也可以使用表别名, 还可以使用完整的数据库限定名
from(‘tbl_user u, public.tbl_profile p‘);

WHERE子句

// 在where()中使用 AND
where(array(‘and‘, ‘id=:id‘, ‘username=:username‘), array(‘:id‘=>$id, ‘:username‘=>$username);
// 在where()中使用 OR 与 AND用法相同,如下:  ##看起来比直接写更加繁琐##
where( array(‘and‘, ‘type=1‘, array(‘or‘, ‘id=:id‘,‘username=:username‘) ),array(‘:id‘=>$id, ‘:username‘=>$username ));

IN 操作符用法

where(array(‘in‘, ‘id‘, array(1,2,3)))

LIKE用法

where( array(‘like‘, ‘name‘, ‘%tester%‘) );
where( array(‘like‘,‘name‘, array(‘%test%‘, ‘%sample%‘)) ) // 等于 name LIKE ‘%test%‘ AND name LIKE ‘%sample%
// 再这样复杂下去, 使用这种方法简直是自杀行为。

$keyword=$ GET[‘q‘];
// escape % and characters
$keyword=strtr($keyword, array(‘%‘=>‘n%‘, ‘ ‘=>‘n ‘));
$command->where(array(‘like‘, ‘title‘, ‘%‘.$keyword.‘%‘));

添加了这么多,你都不知道合成后的SQL长啥样了,可以使用->text()查看(魔术方法)
如果觉得组合的SQL没有错误,那就执行他,添加->queryAll(); 这可以获得所有匹配的结果集。
当然,如果你确定执行的结果集中只有一行,可以添加->queryRow();来直接获取。
如果一个CDbCommand对象需要执行多次,那么在下一次执行之前记得调用reset();

$command = Yii::app()->db->createCommand();
$users = $command->select(‘*‘)->from(‘tbl_users‘)->queryAll();
$command->reset(); // clean up the previous query
$posts = $command->select(‘*‘)->from(‘tbl_posts‘)->queryAll();

 

热门排行

今日推荐

热门手游