數(shù)據(jù)庫(kù)操作和Model層

2018-11-21 21:28 更新

PHALAPI-入門篇5(數(shù)據(jù)庫(kù)操作和MODEL層)

前言

先在這里感謝phalapi框架創(chuàng)始人@dogstar,為我們提供了這樣一個(gè)優(yōu)秀的開(kāi)源框架.

本小節(jié)主要講解基于notorm的數(shù)據(jù)庫(kù)操作以及使用Model層進(jìn)行快速的數(shù)據(jù)層的開(kāi)發(fā),請(qǐng)確保裝有PDO拓展.

附上:

喵了個(gè)咪的博客:w-blog.cn

官網(wǎng)地址:http://www.phalapi.net/

開(kāi)源中國(guó)Git地址:http://git.oschina.net/dogstar/PhalApi/tree/release

1. 基于PDO的notorm進(jìn)行的數(shù)據(jù)庫(kù)操作

phalapi的數(shù)據(jù)庫(kù)操作是使用的開(kāi)源的notorm進(jìn)行的,notorm是基于PDO鏈接數(shù)據(jù)庫(kù),在框架內(nèi)部默認(rèn)鏈接的是mysql數(shù)據(jù)庫(kù),如需修改鏈接其他數(shù)據(jù)庫(kù)請(qǐng)修改 /PhalApi/PhalApi/DB/NotORM.php中的getPdo方法:

 $dsn = sprintf('mysql:dbname=%s;host=%s;port=%d',
                $dbCfg['name'], 
                isset($dbCfg['host']) ? $dbCfg['host'] : 'localhost', 
                isset($dbCfg['port']) ? $dbCfg['port'] : 3306
            );

再講之前其實(shí)這里是有一個(gè)坑的,機(jī)智的童鞋應(yīng)該發(fā)現(xiàn)了框架自帶的user數(shù)據(jù)庫(kù)里面有一個(gè)以from命名字段,應(yīng)為在notorm生成sql語(yǔ)句的時(shí)候不會(huì)給自動(dòng)自動(dòng)加上引號(hào) ,所以在修改添加刪除有涉及這個(gè)字段的時(shí)候會(huì)報(bào)錯(cuò),所以我們?cè)谶@里把它改成phone(所以大家要注意字段名不能為關(guān)鍵字)

下面我們正式來(lái)講解如何使用,我們先在Demo/Api下面創(chuàng)建一個(gè)DB.php文件作為我們的DB模塊,

<?php
/**
 * 數(shù)據(jù)庫(kù)接口服務(wù)類
 */
class Api_DB extends PhalApi_Api{
    public function getRules(){
        return array(
            'insert' => array(
                'id'    => array('name' => 'id', 'require' => true, 'desc' => '用戶Id'),
                'name'  => array('name' => 'name', 'require' => true, 'desc' => '用戶名稱'),
                'phone' => array('name' => 'phone', 'require' => true, 'desc' => '用戶手機(jī)號(hào)碼'),
            ),
            'select' => array(
                'id' => array('name' => 'id', 'require' => true, 'desc' => '用戶Id'),
            ),
            'update' => array(
                'id'    => array('name' => 'id', 'require' => true, 'desc' => '用戶Id'),
                'name'  => array('name' => 'name', 'require' => true, 'desc' => '用戶名稱'),
                'phone' => array('name' => 'phone', 'require' => true, 'desc' => '用戶手機(jī)號(hào)碼'),
            ),
            'delete' => array(
                'id' => array('name' => 'id', 'require' => true, 'desc' => '用戶Id'),
            ),
        );
    }

一共是增刪改查四個(gè)接口代表四種操作(這里一定要配置好數(shù)據(jù)庫(kù),以及運(yùn)行框架自帶的sql文件phalapi_test.sql)

1.1 insert接口

我們先寫增加接口如下:

/**
 * 新增表服務(wù)
 * @return int id 新增列的Id
 */
public function insert(){
    $data = array(                                               //用數(shù)組構(gòu)成需要插入鍵值一一對(duì)應(yīng)
        'id'    => $this->id,
        'name'  => $this->name,
        'phone' => $this->phone,
    );
    $rs   = DI()->notorm->user->insert($data);                  //執(zhí)行數(shù)據(jù)庫(kù)操作user代表的是表,返回結(jié)果是插入成功的值
    return $rs['id'];                                           //返回插入的id
}

重要的是 $rs = DI()->notorm->user->insert($data); 這段代碼執(zhí)行了sql語(yǔ)句,user是表名(這里的表名會(huì)加下在dbs中配置的表前綴組成一個(gè)完整的表名)我們?cè)囍\(yùn)行一下http://localhost/Public/?service=DB.insert&name=miaomi&phone=13010001000&id=2會(huì)得到以下結(jié)果

1.2 select接口

查詢接口如下:

/**
 * 查詢
 * @return array data 結(jié)果集
 */
public function select(){
    $data   = array();
    $data[] = DI()->notorm->user->select('name,phone')->where('id', $this->id)->fetch();
    $data[] = DI()->notorm->user->select('name,phone')->where('id = ?', $this->id)->fetchAll();
    $data[] = DI()->notorm->user->select('name,phone')->where('id != ?', $this->id)->fetchRows();
    return $data;
}

執(zhí)行http://localhost/Public/?service=DB.select&id=2會(huì)得到以下結(jié)果

為什么會(huì)有這樣的區(qū)別,通過(guò)下面的一些小提示大家就能看到區(qū)別在哪里:

1.2.1 select方法

select方法主要是用來(lái)指定返回值,接受的是一個(gè)string他的作用于真正查詢語(yǔ)句select和from之間填充,大家如果把select('name,phone') 改為 select('*') 就會(huì)得到包括id的所有字段的返回

1.2.2 where方法和排序

where方法是查詢中的重要的一個(gè)環(huán)節(jié)

where('id', $this->id)等同于where('id = ?', $this->id)

where('id != ?', $this->id)這種方式只要是為了指定條件大于,等于,小于,不等于

當(dāng)然如果是需要有多個(gè)條件就使用連續(xù)的where就可以->where('id != ?',1)->where('phone','1301000100')這種形式

關(guān)于排序的使用其實(shí)和where差不多使用->order('字段名')如果要反排序在字段名后面加上DESC

1.2.3 fetch,fetchAll和fetchRows

大家有看到上面執(zhí)行的三條查詢語(yǔ)句后面的結(jié)束放到都不同這里講解一下他們的區(qū)別和怎么用他們使用單獨(dú)去執(zhí)行sql語(yǔ)句

fetch方法是獲取單獨(dú)的一條數(shù)據(jù)返回結(jié)果是不帶下標(biāo)的數(shù)組 ,fetchAll和fetchRows不同在于他們返回的是包含多條數(shù)據(jù)一個(gè)帶下標(biāo)的數(shù)組,可以看到在條件一樣的情況下第一條和第二條查詢出來(lái)的結(jié)果區(qū)別是第二條多了一個(gè)0的下標(biāo),從此可得到如果是確定返回結(jié)果只有一條優(yōu)先使用fetch,如果是多條結(jié)果優(yōu)先使用fetchAll和fetchRows.

fetchAll和fetchRows還提供了一個(gè)功能就是單獨(dú)執(zhí)行sql語(yǔ)句

$sql = 'select * from tbl_user where id = :id';
$params = array(':id' => $this->id);                 //替換:id為請(qǐng)求參數(shù)的id
DI()->notorm->user->queryAll($sql, $params);         //或fetchRows($sql, $params)

這樣就可以執(zhí)行sql語(yǔ)句,包括一些復(fù)雜的查詢sql可以使用此內(nèi)方法執(zhí)行(關(guān)聯(lián)查詢應(yīng)當(dāng)優(yōu)先使用這種形式)

1.3 update接口

修改接口如下:

/**
 * 修改
 */
public function update(){
    $data = array(
        'name'  => $this->name,
        'phone' => $this->phone,
    );
    $rs   = DI()->notorm->user->where('id', $this->id)->update($data);
    if($rs === false){
        throw new PhalApi_Exception_BadRequest('修改數(shù)據(jù)失敗');
    }
}

大家可以試一試執(zhí)行之后是否有修改數(shù)據(jù)庫(kù)http://localhost/Public/?service=DB.update&id=2&phone=13011112222&name=wenwenwen

使用其實(shí)和添加接口差不多只是一個(gè)是吧id作為值,一個(gè)是作為條件

比較值得講一下的是為什么使用if($rs === false)

原因是這樣的,這里執(zhí)行update方法之后獲取得是影響行數(shù),如果原本值就是一樣的那就回返回0,只有在真正語(yǔ)句失敗的時(shí)候會(huì)返回false所以這里使用全等于false作為判斷是否執(zhí)行成功的條件

1.4 delete接口

刪除接口如下:

/**
 * 刪除
 */
public function delete(){
    $rs   = DI()->notorm->user->where('id', $this->id)->delete();
    if($rs === false){
        throw new PhalApi_Exception_BadRequest('刪除數(shù)據(jù)失敗');
    }
}

http://localhost/Public/?service=DB.delete&id=2

刪除的操作也很簡(jiǎn)單,不過(guò)if($rs === false)就算沒(méi)有刪除到數(shù)據(jù)也會(huì)返回成功,只有當(dāng)語(yǔ)句失敗會(huì)反悔false,如果需要未刪除到數(shù)據(jù)提示出錯(cuò)的同學(xué)可以把等號(hào)減少一個(gè)

1.5 打印sql語(yǔ)句

有的時(shí)候光靠自己去看代碼很難確定是不是哪里寫的有問(wèn)題,但是如果查看生成出來(lái)的sql語(yǔ)句就能很快的確定問(wèn)題出現(xiàn)在哪里

大家可以試試在請(qǐng)求參數(shù)中加上 就可以打印出來(lái)生成的sql語(yǔ)句方便調(diào)試

包括執(zhí)行時(shí)間和先后順序也一同打印出來(lái)了,也可以幫助大家找到慢查詢?cè)谀睦?/p>

2. 使用Model進(jìn)行數(shù)據(jù)庫(kù)操作

使用Model操作是為了提高開(kāi)發(fā)效率,讓同樣數(shù)據(jù)庫(kù)操作可以進(jìn)行高度的復(fù)用,也便于修改起來(lái)改一處則全改這種效果

2.1 傳統(tǒng)的Model操作

所謂傳統(tǒng)的Model操作也就是把數(shù)據(jù)操作封裝起來(lái),方便調(diào)用比如/Model/User.php下面的getByUserId方法

public function getByUserId($userId) {
    return DI()->notorm->user->select('*')->where('id = ?', $userId)->fetch();
}

在內(nèi)部直接封裝數(shù)據(jù)庫(kù)操作使用如下代碼調(diào)用

    $model = new Model_User();
    $rs = $model->getByUserId($userId);

2.2 框架自帶的Model操作

當(dāng)然這里介紹model的目的當(dāng)然是解讀一下phalapi內(nèi)部提供的model操作

使用自帶model操作只需要繼承PhalApi_Model_NotORM 在實(shí)現(xiàn)如下方法

protected function getTableName($id) {
    return 'user';
}

這個(gè)方法主要作用是為了添加這個(gè)model 的表名,其實(shí)這兩個(gè)操作在/Model/User.php中已經(jīng)實(shí)現(xiàn)了,我們來(lái)重構(gòu)一下getByUserId方法如下

public function getByUserId($userId) {
    return $this->getORM()->select('*')->where('id = ?', $userId)->fetch();
}

$this->getORM()相當(dāng)于DI()->notorm->(getTableName中設(shè)置的表名)

然后我們重寫select接口如下:

public function select(){
    $model = new Model_User();
    return $model->getByUserId($this->id);
}

可以獲得以下結(jié)果

在這里phalapi自帶的model和傳統(tǒng)的model對(duì)比起來(lái)區(qū)別在于,phalapi統(tǒng)一制定表名不會(huì)應(yīng)為方法果斷導(dǎo)致的表名寫錯(cuò)的失誤

另一方面phalapi自帶的model提供了很多字基礎(chǔ)操作,利用自動(dòng)提示功能可以看到

我們來(lái)再次改造一下selete接口使用model自帶的方法

public function select(){
    $model = new Model_User();
    return $model->get($this->id);
}

執(zhí)行結(jié)果和上面是一樣的,這里注意一點(diǎn)這里Id的名字是dbs中配置的'key' => 'id',要和數(shù)據(jù)庫(kù)中的ID字段名對(duì)應(yīng),但是這樣會(huì)有一些問(wèn)題會(huì)在后面進(jìn)階篇提及到

3. 總結(jié)

在本小節(jié)著重講了CURD操作,以及其中的一些操作的使用和怎么使用phalapi的model層,希望大家看完本小節(jié)之后進(jìn)行一些練習(xí)來(lái)熟練的掌握使用phalapi對(duì)數(shù)據(jù)庫(kù)的操作,關(guān)于數(shù)據(jù)庫(kù)操作的一些小技巧會(huì)單獨(dú)在進(jìn)階篇中抽出一小節(jié)來(lái)講講在實(shí)際項(xiàng)目開(kāi)發(fā)中遇到的問(wèn)題以及如何解決,希望大家進(jìn)一步關(guān)注!

注:筆者能力有限有說(shuō)的不對(duì)的地方希望大家能夠指出,也希望多多交流!

官網(wǎng)QQ交流群:421032344 歡迎大家的加入!

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)