Yii数据库操作方法指南

CDbConnection: 一个抽象数据库连接

CDbCommand: SQL statement CDbDataReader: 匹配结果集的一行记录 CDbTransaction:数据库事务 访问数据库前需要建立数据库连接;使用DAO建立一个抽象数据库链接: $connection = new CDbConnection($dsn, $username, $password); $connection->active = true;     // 只有激活了连接才可以使用 $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')); // 使用form() 如果制定了多个表需要使用逗号分隔的字符串,就像原生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(); /// YII的SQL构建函数就是一鸡肋。 // Active Record // 使用AR以面向对象的方式访问数据库,AR实现了ORM技术 // 当Post类表示表tbl_post时,我们可以使用这样的方式插入一条数据 $post = new Post(); $post->title = 'new title'; $post->content = 'new content'; $post->save();      // 保存即插入 // AR最典型的功能就是执行CRUD操作 // DAO定位于解决复杂的数据库查询,而AR定位于解决简单的数据库查询 // 一个AR类代表一张数据表,而一个AR对象代表表中的一行真实的记录,AR类继承CActiveRecord。 // 如果有一张POST表`tbl_post`,你可以这样定义一个AR类 class Post extends CACtiveRecord {     public static function model($className = __CLASS__)     {         return parent::model($className);     }     public function tablName()     {         return '{{post}}';     } } // 表中的每一个字段都由AR类中的一个属性表示,如果试图通过属性访问表中没有字段,将会抛出一个异常。 // 一个AR一定需要一个主键,如果某张表没有主键,你就自己在类中伪造一个,像这样: public function primaryKey() {     return 'id';        // 'id' 是关联表中的一个字段,但他不是主键,现在将它指定为主键 } // 实例化一个AR,填写信息(类似于填充用户提交的信息),然后保存 $post = new Post; $post->title = 'sample post'; $post->content = 'content for the sample post'; $post->create_time = time(); $post->save();  // 保存/插入 // 通过AR读取记录 find() findByPk() findByAttributes() findBySql() $post=Post::model()->find($condition,$params);                  // 返回Post对象(如果有匹配记录的话), 否则返回NULL $post=Post::model()->findByPk($postID,$condition,$params); $post=Post::model()->findByAttributes($attributes,$condition,$params); $post=Post::model()->findBySql($sql,$params); // find()的一个例子: $post=Post::model()->find('postID=:postID', array(':postID'=>10)); // 如果查询条件很是复杂,就要使用CDbCriteria类 $criteria = new CDbCriteria; $criteria->select='title'; $creteria->condition='postID=:postID'; $criteria->params=array(':postID'=>10); $post=Post::model()->find($criteria);   // 不需要第二个参数 // 另一种更好的写法 $post=Post::model()->find(array(         'select' => 'title',         'condition' => 'postID=:postID',         'params' => array(':postID' => 10)         )); // 如果查找的是多行记录可以使用 findAll() findAllByPk() findAllByAttributes() findAllBySql() // find all rows satisfying the specified condition $posts=Post::model()->findAll($condition,$params); // find all rows with the specified primary keys $posts=Post::model()->findAllByPk($postIDs,$condition,$params); // find all rows with the specified attribute values $posts=Post::model()->findAllByAttributes($attributes,$condition,$params); // find all rows using the specified SQL statement $posts=Post::model()->findAllBySql($sql,$params); // 如果没有匹配的行,将返回一个空数组,这可以用empty()去检测 // 另外的一些可以使用的方法: // get the number of rows satisfying the specified condition $n=Post::model()->count($condition,$params); // get the number of rows using the specified SQL statement $n=Post::model()->countBySql($sql,$params); // check if there is at least a row satisfying the specified condition $exists=Post::model()->exists($condition,$params); // 使用AR更新记录 // 一个典型的实例: $post=Post::model()->findByPk(10); $post->title='new post title'; $post->save(); // save the change to database // 怎么知道这是一条新纪录还是一条旧的记录呢?使用如下方法: if( CActiveRecord::isNewRecord ) // update the rows matching the specified condition Post::model()->updateAll($attributes,$condition,$params); // update the rows matching the specified condition and primary key(s) Post::model()->updateByPk($pk,$attributes,$condition,$params); // update counter columns in the rows satisfying the specified conditions Post::model()->updateCounters($counters,$condition,$params); // 删除记录 $post=Post::model()->findByPk(10); // assuming there is a post whose ID is 10 $post->delete(); // delete the row from the database table // 注意,当删除记录之后,$post仍然可用, 且保留了原始数据。 // 类级别的方法 // delete the rows matching the specified condition Post::model()->deleteAll($condition,$params); // delete the rows matching the specified condition and primary key(s) Post::model()->deleteByPk($pk,$condition,$params); // 数据验证 // 将用户提交的数据保存到AR对象中 $post->title = $_POST['title']; $post->content = $_POST['content']; $post->save(); // assume $ POST['Post'] is an array of column values indexed by column names $post->attributes=$ POST['Post']; $post->save(); // RAR:Relatived Actie Record // RAR本质上就是执行关系数据查询 // 如何让一个AR关联另一个AR // 4中关系类型 self::BELONGS_TO self::HAS_MANY self::HAS_ONE self::MANY_MANY 关系名称(关系类型,要关联的类名,外键名,其他额外的选项); // 定义表关系 类:Post public function relations() {     return array(         'author'=>array(self::BELONGS_TO, 'User', 'author_id'),     // 返回User对象         'categories'=>array(self::MANY_MANY, 'Category', 'tbl_post_category(post_id, category_id)'),     ); } // 类:User public function relations() {     return array(             'posts' => array(self::HAS_MANY, 'Post', 'author_id'),             'profile' => array(self::HAS_ONE, 'Profile', 'owner_id')     ); } // 定义了AR间的关系之后,当执行关系查询时,与AR关联的AR也会自动实例化, 比如这样: $author = User::model()->findByPk(1); $author->posts;         // posts关系已经定义。 // 执行关系查询 1).lazy loading approach 懒惰关系执行 // retrieve the post whose ID is 10 $post=Post::model()->findByPk(10); // retrieve the post's author: a relational query will be performed here $author=$post->author;  // 如果先前没有执行过,现在才执行这个关系查询(事情拖到这一步才做,真的是很懒啊!) // 如果关系查询执行后没有匹配的结果,返回将会是NULL或空的数组。 2).eager loading approach   热心的关系查询 //这名字真的很萌! // 也就是说一次性取回所有你想要的记录。管你要不要,这这这,太热心了吧! $posts=Post::model()->with('author')->findAll(); // SQL => 'SELECT tbl_post.*, author.* FROM tbl_post t INNER JOIN tbl_user author ON t.author = tbl_user.id' $posts=Post::model()->with('author','categories')->findAll(); // SQL => 'SELECT * FROM tbl_post t INNER JOIN tbl_user u ON t.author = u.id INNER JOIN categories c ON t.id = c.post_id' $posts=Post::model()->with(     'author.profile',     'author.posts',     'categories')->findAll(); $criteria=new CDbCriteria; $criteria->with=array( 'author.profile', 'author.posts', 'categories', ); $posts=Post::model()->findAll($criteria); 或者 $posts=Post::model()->findAll(array(                                     'with'=>array(                                     'author.profile',                                     'author.posts',                                     'categories',                                     )                              ); // 如果我们想知道用户中谁发过帖子,并且帖子的状态是“公开”。我们并不关心用户发表过的帖子的内容。 $user = User::model()->with('posts')->findAll();                 'VS' $user = User::model()->with(array(                                     'posts' => array(                                                         'select' => false,                                                         'joinType' => 'INNER JOIN',                                                         'condition' => 'posts.published = 1'                                                     ),                                  )                            )->findAll(); // 返回的将会是所有发过帖子(且帖子已经公开)的用户 // 在relatinos()中定义更加复杂的关系 class User extends CActiveRecord {     public function relations()     {             return array(                     'posts'=>array(self::HAS MANY, 'Post', 'author id',                     'order'=>'posts.create time DESC',                     'with'=>'categories'),                     'profile'=>array(self::HAS ONE, 'Profile', 'owner id'),                     );     } } // 利用别名解决歧义 $posts=Post::model()->with('comments')->findAll(array(         'order'=>'t.create time, comments.create time'     )); // Dynamic Relational Query 动态关系SQL查询,更改默认插叙条件: User::model()->with(array(         'posts'=>array('order'=>'posts.create time ASC'),         'profile',     ))->findAll(); $user=User::model()->findByPk(1); $posts=$user->posts(array('condition'=>'status=1'));        // 返回的都是AR对象, 而不是数据 // 统计查询 class Post extends CActiveRecord {     public function relations()     {         return array(             'commentCount'=>array(self::STAT, 'Comment', 'post_id'),             'categoryCount'=>array(self::STAT, 'Category', 'post_category(post_id, category_id)'),         );     }

}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏逸鹏说道

不同场景下 MySQL 的迁移方案

不同场景下 MySQL 的迁移方案 一 目录 一 目录 二 为什么要迁移 三 MySQL 迁移方案概览 四 MySQL 迁移实战 4.1 场景一 一主一从结构迁...

47180
来自专栏灯塔大数据

每周学点大数据 | No.2大数据的特点、应用和算法

No.2期 大数据的特点、应用和算法 一、大数据的特点和应用 Mr. 王:大数据具有较大的数据量,和一般的数据相比,其具有如下一些特点。 ? —在数据量上,大...

36940
来自专栏灯塔大数据

洞察|iPhone7来临前的大数据分析

每年8、9月都能迎来智能手机界的更新热潮,其中最受关注的新iPhone通常都是在九月份与大家见面,而其他品牌大多会选择避开9月这个非常时期,在8月或者10月带...

30380
来自专栏灯塔大数据

干货|在选择数据库的路上,我们遇到过哪些坑?

我是 FactGem 的首席技术官 Clark Richey。FactGem 是一家小公司。 在这里我想说一说我们是怎么开始接触数据库技术的,然后我们做出了哪...

30770
来自专栏逸鹏说道

EntityFramework 外键值映射

如果在 EF OnModelCreating 中配置了实体外键映射,也就是 SQL Server 中的 ForeignKey,那么我们在添加实体的时候,主实体的...

1K50
来自专栏灯塔大数据

每周学点大数据 | No.4算法的分析之时间复杂度

No.4期 算法的分析之时间复杂度 小可:嗯,我觉得评价一个算法的最基本方式就是看它运行得快不快。 Mr. 王:嗯,这是重要的考量标准之一。研究算法运行得快不...

30290
来自专栏逸鹏说道

大型.NET ERP系统的20条数据库设计规范

数据库设计规范是个技术含量相对低的话题,只需要对标准和规范的坚持即可做到。当系统越来越庞大,严格控制数据库的设计人员,并且有一份规范书供执行参考。在程序框架中,...

39260
来自专栏逸鹏说道

SQL vs NoSQL:如何选择?

SQL 数据库: 在表中存储相关联的数据 在使用之前需要定义表的一个模式 鼓励标准化减少数据冗余 支持从多个表中检索相关数据表连接在一个单一的命令 实现数据完整...

35950
来自专栏开源优测

[快学Python3]PyMySQL库

概述 本文主要讲解如何使用pymysql库进行MySQL的管理操作。 主要讲解如何使用pymysql实现增删改查动作,并附上对应的示例。 安装pymysql p...

47490
来自专栏逸鹏说道

触发器在渗透中的利用

0x01 什么是触发器: 触发器对表进行插入、更新、删除的时候会自动执行的特殊存储过程。触发器一般用在check约束更加复杂的约束上面。触发器和普通的存储过程的...

38750

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励