Yii数据库操作方法指南
CDbConnection: 一个抽象数据库连接
CDbCommand: SQL statement
CDbDataReader: 匹配结果集的一行记录
CDbTransaction:数据库事务
访问数据库前需要建立数据库连接;使用DAO建立一个抽象数据库链接:
connection=newCDbConnection(connection=newCDbConnection(dsn, username,username,password);
connection−>active=true;//只有激活了连接才可以使用connection−>active=true;//只有激活了连接才可以使用connection->active = false; // 关闭连接
CDbConnection继承自CApplicationComponent,所以他可以像组件一样在任何地方使用。因此可以这样访问:
Yii::app()->db
//执行SQL语句需要CDbCommand对象,而该对象由CdbConnection::createCommand()返回,因此:
connection=Yii::app()−>db;connection=Yii::app()−>db;command=connection−>createCommand(connection−>createCommand(sql);
// 如果SQL语句想要完全有自己写,可以这样:
newSQL=′SQL语句′;newSQL=′SQL语句′;command->text=newSQL;//CDbCommand对象有两个方法execute()用于非查询SQL执行,而query(),通俗的讲就是用于SELECT查询//execute()返回的是INSERT,UPDATEandDELETE操作受影响的记录行数//query()返回一个CDbDataReader对象,使用CDbDataReader对象可以遍历匹配结果集中的所有记录。newSQL;//CDbCommand对象有两个方法execute()用于非查询SQL执行,而query(),通俗的讲就是用于SELECT查询//execute()返回的是INSERT,UPDATEandDELETE操作受影响的记录行数//query()返回一个CDbDataReader对象,使用CDbDataReader对象可以遍历匹配结果集中的所有记录。rowCount=command−>execute();//executethenon−querySQLcommand−>execute();//executethenon−querySQLdataReader=command−>query();//executeaquerySQL//返回CDbDataReader对像command−>query();//executeaquerySQL//返回CDbDataReader对像rows=command−>queryAll();//queryandreturnallrowsofresultcommand−>queryAll();//queryandreturnallrowsofresultrow=command−>queryRow();//queryandreturnthefirstrowofresultcommand−>queryRow();//queryandreturnthefirstrowofresultcolumn=command−>queryColumn();//queryandreturnthefirstcolumnofresultcommand−>queryColumn();//queryandreturnthefirstcolumnofresultvalue=command−>queryScalar();//queryandreturnthefirstfieldinthefirstrow//query()返回的是代表结果集的对象而非直接的结果,因此要获取结果集的记录可以这样:command−>queryScalar();//queryandreturnthefirstfieldinthefirstrow//query()返回的是代表结果集的对象而非直接的结果,因此要获取结果集的记录可以这样:dataReader=command−>query();//CDbDataReader::read()可以一次获取一行数据,到末尾时返回falsewhile((command−>query();//CDbDataReader::read()可以一次获取一行数据,到末尾时返回falsewhile((row=dataReader−>read())!==false)//CDbDataReader实现了迭代器接口因此可以使用foreach遍历foreach(dataReader−>read())!==false)//CDbDataReader实现了迭代器接口因此可以使用foreach遍历foreach(dataReader as row)//一次性返回所有的记录(数组)row)//一次性返回所有的记录(数组)rows=dataReader−>readAll();queryXXX()形式的方法会直接返回匹配的记录集合,当query()不是,他返回一个代表结果集的对象//YII中的CDbTransaction类用于事务//首先,建立一个连接dataReader−>readAll();queryXXX()形式的方法会直接返回匹配的记录集合,当query()不是,他返回一个代表结果集的对象//YII中的CDbTransaction类用于事务//首先,建立一个连接connection = Yii::app()->db;
// 第二,开始事务
transaction=transaction=connection->beginTransaction();
// 第三,执行SQL,如果错误就抛出异常,在异常处理中回滚。
try
{
connection−>createCommand(connection−>createCommand(sql1)->execute();
connection−>createCommand(connection−>createCommand(sql2)->execute();
//.... other SQL executions
// 如果SQL执行都没有抛出异常,那就提交。
transaction->commit(); } catch(Exceptiontransaction->commit(); } catch(Exceptione) {
[Math Processing Error]connection = Yii::app()->db;
// 第二,写下无敌的SQL语句,比如:
sql="INSERTINTOtbluser(username,email)VALUES(:username,:email)";//第三,创建CDbCommand对象用于执行SQLsql="INSERTINTOtbluser(username,email)VALUES(:username,:email)";//第三,创建CDbCommand对象用于执行SQLcommand=connection−>createCommand(connection−>createCommand(sql);
// 接下来,将SQL语句中的形式参数,替换为实际参数
command−>bindParam(":username",command−>bindParam(":username",username,PDO::PARAM STR); // 这与PDO有点不同,PDO中不带冒号
command−>bindParam(":email",command−>bindParam(":email",email,PDO::PARAM STR); // 同样
// 最后,执行
command−>execute();//如果还有其他的数据需要插入,可以再次绑定实参。//使用CDbDataReader对象的bindColumn()方法将结果集中的列绑定到PHP变量。//因此,读取一行记录,列值将自动填充到对应的PHP对象中//比如这样:command−>execute();//如果还有其他的数据需要插入,可以再次绑定实参。//使用CDbDataReader对象的bindColumn()方法将结果集中的列绑定到PHP变量。//因此,读取一行记录,列值将自动填充到对应的PHP对象中//比如这样:connection = Yii::app()->db;
sql="SELECTusername,emailFROMtbluser";sql="SELECTusername,emailFROMtbluser";dataReader = connection−>createCommand(connection−>createCommand(sql)->query(); //很赞的方法链, 可惜不能接着.each()
dataReader−>bindColumn(1,dataReader−>bindColumn(1,username); //第一列值绑定到usernameusernamedataReader->bindColumn(2, email);//第二列值绑定到email);//第二列值绑定到email
//接着循环读取并操作数据
while( dataReader−>read()!==false)...//与先前的while(($row=$dataReader−>read())!==false)有所不同哦!//设置表前缀,使用CDbConnection::tablePrefix属性在配置文件中设置////Yii实现了把一条完整的SQL语句完完全全肢解的能力,比如这样: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();//返回匹配的结果集的第一行//其实这条语句是这样的: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子句中构建INNERJOIN子句−>leftJoin():在FROM子句中构建左连接子句−>rightJoin():在FROM子句中构建右连接子句−>crossJoin():添加交叉查询片段(没用过)−>naturalJoin():添加一个自然连接子片段−>group():GROUPBY子句−>having():类似于WHERE的子句,但要与GROUPBY连用−>order():ORDERBY子句−>limit():LIMIT子句的第一部分−>offset():LIMIT子句的第二部分−>union():appendsaUNIONqueryfragmentselect()默认返回全部列//但你可以这样:select(′username,email′);//或使用表限定,或使用别名select(′tbluser.id,usernamename′);//或使用数组作为参数select(array(′id′,′count(∗)asnum′));//使用form()如果制定了多个表需要使用逗号分隔的字符串,就像原生SQL语句那样:from(′tbluser,tblpost,tblprofile′);//当然,你也可以使用表别名,还可以使用完整的数据库限定名from(′tbluseru,public.tblprofilep′);WHERE子句//在where()中使用ANDwhere(array(′and′,′id=:id′,′username=:username′),array(′:id′=>command=Yii::app()−>db−>createCommand();//注意参数留空了。。//可用的方法列表如下:−>select():SELECT子句−>selectDistinct():SELECT子句,并保持了记录的唯一性−>from():构建FROM子句−>where():构建WHERE子句−>join():在FROM子句中构建INNERJOIN子句−>leftJoin():在FROM子句中构建左连接子句−>rightJoin():在FROM子句中构建右连接子句−>crossJoin():添加交叉查询片段(没用过)−>naturalJoin():添加一个自然连接子片段−>group():GROUPBY子句−>having():类似于WHERE的子句,但要与GROUPBY连用−>order():ORDERBY子句−>limit():LIMIT子句的第一部分−>offset():LIMIT子句的第二部分−>union():appendsaUNIONqueryfragmentselect()默认返回全部列//但你可以这样:select(′username,email′);//或使用表限定,或使用别名select(′tbluser.id,usernamename′);//或使用数组作为参数select(array(′id′,′count(∗)asnum′));//使用form()如果制定了多个表需要使用逗号分隔的字符串,就像原生SQL语句那样:from(′tbluser,tblpost,tblprofile′);//当然,你也可以使用表别名,还可以使用完整的数据库限定名from(′tbluseru,public.tblprofilep′);WHERE子句//在where()中使用ANDwhere(array(′and′,′id=:id′,′username=:username′),array(′:id′=>id, ':username'=>[Math Processing Error]id, ':username'=>username));//IN操作符用法where(array(′in′,′id′,array(1,2,3)))//LIKE用法where(array(′like′,′name′,′username));//IN操作符用法where(array(′in′,′id′,array(1,2,3)))//LIKE用法where(array(′like′,′name′,′keyword=GET[′q′];//escapeGET[′q′];//escapekeyword=strtr(keyword,array(′keyword,array(′command->where(array('like', 'title', '%'.keyword.′keyword.′command = Yii::app()->db->createCommand();
users=users=command->select('*')->from('tbl_users')->queryAll();
command−>reset();//cleanupthepreviousquerycommand−>reset();//cleanupthepreviousqueryposts = command−>select(′∗′)−>from(′tblposts′)−>queryAll();///YII的SQL构建函数就是一鸡肋。//ActiveRecord//使用AR以面向对象的方式访问数据库,AR实现了ORM技术//当Post类表示表tblpost时,我们可以使用这样的方式插入一条数据command−>select(′∗′)−>from(′tblposts′)−>queryAll();///YII的SQL构建函数就是一鸡肋。//ActiveRecord//使用AR以面向对象的方式访问数据库,AR实现了ORM技术//当Post类表示表tblpost时,我们可以使用这样的方式插入一条数据post = new Post();
post−>title=′newtitle′;post−>title=′newtitle′;post->content = 'new content';
[Math Processing Error]post = new Post;
post−>title=′samplepost′;post−>title=′samplepost′;post->content = 'content for the sample post';
post−>createtime=time();post−>createtime=time();post->save(); // 保存/插入
// 通过AR读取记录 find() findByPk() findByAttributes() findBySql()
post=Post::model()−>find(post=Post::model()−>find(condition,params);//返回Post对象(如果有匹配记录的话),否则返回NULLparams);//返回Post对象(如果有匹配记录的话),否则返回NULLpost=Post::model()->findByPk(postID,postID,condition,params);params);post=Post::model()->findByAttributes(attributes,attributes,condition,params);params);post=Post::model()->findBySql(sql,sql,params);
// find()的一个例子:
post=Post::model()−>find(′postID=:postID′,array(′:postID′=>10));//如果查询条件很是复杂,就要使用CDbCriteria类post=Post::model()−>find(′postID=:postID′,array(′:postID′=>10));//如果查询条件很是复杂,就要使用CDbCriteria类criteria = new CDbCriteria;
criteria−>select=′title′;criteria−>select=′title′;creteria->condition='postID=:postID';
criteria−>params=array(′:postID′=>10);criteria−>params=array(′:postID′=>10);post=Post::model()->find(criteria);//不需要第二个参数//另一种更好的写法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(posts=Post::model()−>findAll(condition,params);//findallrowswiththespecifiedprimarykeysparams);//findallrowswiththespecifiedprimarykeysposts=Post::model()->findAllByPk(postIDs,postIDs,condition,params);//findallrowswiththespecifiedattributevaluesparams);//findallrowswiththespecifiedattributevaluesposts=Post::model()->findAllByAttributes(attributes,attributes,condition,params);//findallrowsusingthespecifiedSQLstatementparams);//findallrowsusingthespecifiedSQLstatementposts=Post::model()->findAllBySql(sql,sql,params);
// 如果没有匹配的行,将返回一个空数组,这可以用empty()去检测
// 另外的一些可以使用的方法:
// get the number of rows satisfying the specified condition
n=Post::model()−>count(n=Post::model()−>count(condition,params);//getthenumberofrowsusingthespecifiedSQLstatementparams);//getthenumberofrowsusingthespecifiedSQLstatementn=Post::model()->countBySql(sql,sql,params);
// check if there is at least a row satisfying the specified condition
exists=Post::model()−>exists(exists=Post::model()−>exists(condition,params);//使用AR更新记录//一个典型的实例:params);//使用AR更新记录//一个典型的实例:post=Post::model()->findByPk(10);
post−>title=′newposttitle′;post−>title=′newposttitle′;post->save(); // save the change to database
// 怎么知道这是一条新纪录还是一条旧的记录呢?使用如下方法:
if( CActiveRecord::isNewRecord )
// update the rows matching the specified condition
Post::model()->updateAll(attributes,attributes,condition,params);//updatetherowsmatchingthespecifiedconditionandprimarykey(s)Post::model()−>updateByPk(params);//updatetherowsmatchingthespecifiedconditionandprimarykey(s)Post::model()−>updateByPk(pk,attributes,attributes,condition,params);//updatecountercolumnsintherowssatisfyingthespecifiedconditionsPost::model()−>updateCounters(params);//updatecountercolumnsintherowssatisfyingthespecifiedconditionsPost::model()−>updateCounters(counters,condition,condition,params);
// 删除记录
post=Post::model()−>findByPk(10);//assumingthereisapostwhoseIDis10post=Post::model()−>findByPk(10);//assumingthereisapostwhoseIDis10post->delete(); // delete the row from the database table
// 注意,当删除记录之后,post仍然可用,且保留了原始数据。//类级别的方法//deletetherowsmatchingthespecifiedconditionPost::model()−>deleteAll(post仍然可用,且保留了原始数据。//类级别的方法//deletetherowsmatchingthespecifiedconditionPost::model()−>deleteAll(condition,params);//deletetherowsmatchingthespecifiedconditionandprimarykey(s)Post::model()−>deleteByPk(params);//deletetherowsmatchingthespecifiedconditionandprimarykey(s)Post::model()−>deleteByPk(pk,condition,condition,params);
// 数据验证
// 将用户提交的数据保存到AR对象中
post−>title=post−>title=_POST['title'];
post−>content=post−>content=_POST['content'];
post−>save();//assumepost−>save();//assume POST['Post'] is an array of column values indexed by column names
post−>attributes=post−>attributes= POST['Post'];
post−>save();//RAR:RelativedActieRecord//RAR本质上就是执行关系数据查询//如何让一个AR关联另一个AR//4中关系类型self::BELONGSTOself::HASMANYself::HASONEself::MANYMANY关系名称(关系类型,要关联的类名,外键名,其他额外的选项);//定义表关系类:Postpublicfunctionrelations()returnarray(′author′=>array(self::BELONGSTO,′User′,′authorid′),//返回User对象′categories′=>array(self::MANYMANY,′Category′,′tblpostcategory(postid,categoryid)′),);//类:Userpublicfunctionrelations()returnarray(′posts′=>array(self::HASMANY,′Post′,′authorid′),′profile′=>array(self::HASONE,′Profile′,′ownerid′));//定义了AR间的关系之后,当执行关系查询时,与AR关联的AR也会自动实例化,比如这样:post−>save();//RAR:RelativedActieRecord//RAR本质上就是执行关系数据查询//如何让一个AR关联另一个AR//4中关系类型self::BELONGSTOself::HASMANYself::HASONEself::MANYMANY关系名称(关系类型,要关联的类名,外键名,其他额外的选项);//定义表关系类:Postpublicfunctionrelations()returnarray(′author′=>array(self::BELONGSTO,′User′,′authorid′),//返回User对象′categories′=>array(self::MANYMANY,′Category′,′tblpostcategory(postid,categoryid)′),);//类:Userpublicfunctionrelations()returnarray(′posts′=>array(self::HASMANY,′Post′,′authorid′),′profile′=>array(self::HASONE,′Profile′,′ownerid′));//定义了AR间的关系之后,当执行关系查询时,与AR关联的AR也会自动实例化,比如这样:author = User::model()->findByPk(1);
author−>posts;//posts关系已经定义。//执行关系查询1).lazyloadingapproach懒惰关系执行//retrievethepostwhoseIDis10author−>posts;//posts关系已经定义。//执行关系查询1).lazyloadingapproach懒惰关系执行//retrievethepostwhoseIDis10post=Post::model()->findByPk(10);
// retrieve the post's author: a relational query will be performed here
author=author=post->author; // 如果先前没有执行过,现在才执行这个关系查询(事情拖到这一步才做,真的是很懒啊!)
// 如果关系查询执行后没有匹配的结果,返回将会是NULL或空的数组。
2).eager loading approach 热心的关系查询 //这名字真的很萌!
// 也就是说一次性取回所有你想要的记录。管你要不要,这这这,太热心了吧!
posts=Post::model()−>with(′author′)−>findAll();//SQL=>′SELECTtblpost.∗,author.∗FROMtblposttINNERJOINtbluserauthorONt.author=tbluser.id′posts=Post::model()−>with(′author′)−>findAll();//SQL=>′SELECTtblpost.∗,author.∗FROMtblposttINNERJOINtbluserauthorONt.author=tbluser.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();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.createtime,comments.createtime′));//DynamicRelationalQuery动态关系SQL查询,更改默认插叙条件:User::model()−>with(array(′posts′=>array(′order′=>′posts.createtimeASC′),′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)'),
);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~