YII訪問數據庫(Yii Dao)

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讀取記錄 fine() 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)'),
        );
    }
sql

}數據庫

相關文章
相關標籤/搜索