国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

寫(xiě)一個(gè)“特殊”的查詢(xún)構(gòu)造器 - (七、DML 語(yǔ)句、事務(wù))

lookSomeone / 2529人閱讀

摘要:同樣的,添加屬性,修改函數(shù)構(gòu)造語(yǔ)句的方法基類(lèi)中添加方法檢測(cè)有沒(méi)有設(shè)置子句構(gòu)建語(yǔ)句參數(shù)綁定返回影響的行數(shù)更新數(shù)據(jù)示例相比,語(yǔ)句更為簡(jiǎn)單,只需子句即可。

查詢(xún)語(yǔ)句 (DQL) 的構(gòu)造功能開(kāi)發(fā)完畢,我們?cè)俳o查詢(xún)構(gòu)造器增加一些對(duì) DML (Data Manipulation Language) 語(yǔ)句的支持,如簡(jiǎn)單的 insert、update、delete 操作。

insert

我們先回顧下 PDO 原生的 insert 操作怎么進(jìn)行:

// 預(yù)編譯
$pdoSt = $pdo->prepare("INSERT INTO test_table ("username", "age") VALUES (:username, :age);");
// 綁定參數(shù)
$pdoSt->bindValue(":username", "Jack", PDO::PARAM_STR)
$pdoSt->bindValue(":age", 18, PDO::PARAM_INT)
// 執(zhí)行
$pdoSt->execute(); 
// 獲取執(zhí)行數(shù)據(jù)
$count = $pdoSt->rowCount(); // 返回被影響的行數(shù)
$lastId = $pdo->lastInsertId(); // 獲取最后插入行的 ID

數(shù)據(jù)插入

和查詢(xún)語(yǔ)句的執(zhí)行過(guò)程并沒(méi)有太大差別,只是語(yǔ)法不同。回想第二篇,我們新建了 _buildQuery() 方法去構(gòu)造最終的 SQL,對(duì)于 insert,我們?cè)诨?lèi)新建 _buildInsert() 方法:

protected function _buildInsert()
{
    $this->_prepare_sql = "INSERT INTO ".$this->_table.$this->_insert_str;
}

基類(lèi)添加 _insert_str 屬性:

protected $_insert_str = "";

修改 _reset() 函數(shù),將 _insert_str 屬性的初始化過(guò)程添加進(jìn)去:

protected function _reset()
{
    $this->_table = "";
    $this->_prepare_sql = "";
    $this->_cols_str = " * ";
    $this->_where_str = "";
    $this->_orderby_str = "";
    $this->_groupby_str = "";
    $this->_having_str = "";
    $this->_join_str = "";
    $this->_limit_str = "";
    $this->_insert_str = ""; // 重置 insert 語(yǔ)句
    $this->_bind_params = [];
}

基類(lèi)中添加 insert() 方法:

public function insert(array $data)
{
    // 構(gòu)建字符串
    $field_str = "";
    $value_str = "";
    foreach ($data as $key => $value) {
        $field_str .= " ".self::_wrapRow($key).",";
        $plh = self::_getPlh(); // 生產(chǎn)占位符
        $this->_bind_params[$plh] = $value; //保存綁定數(shù)據(jù)
        $value_str .= " ".$plh.",";
    }
    // 清除右側(cè)多余的逗號(hào)
    $field_str = rtrim($field_str, ",");
    $value_str = rtrim($value_str, ",");

    $this->_insert_str = " (".$field_str.") VALUES (".$value_str.") ";
    // 構(gòu)造 insert 語(yǔ)句
    $this->_buildInsert();
    // 執(zhí)行
    $this->_execute();
    // 獲取影響的行數(shù)
    return $this->_pdoSt->rowCount();
}

對(duì)上述代碼,我們申明了 insert() 方法的參數(shù)是一個(gè)鍵值數(shù)組,用來(lái)傳入要插入的字段、值映射。默認(rèn)返回被影響的行數(shù) (比較通用)。

測(cè)試

試著插入一條數(shù)據(jù)吧:

$insert_data = [
    "username" => "jack",
    "age"      => 18,
];

$results = $driver->table("test_table")->insert($insert_data);

獲取最后插入行的 ID

當(dāng)一個(gè)表中有自增 id 且為主鍵時(shí),這個(gè) id 可以被看作區(qū)分?jǐn)?shù)據(jù)的唯一標(biāo)識(shí)。而在插入一條數(shù)據(jù)后獲取這條新增數(shù)據(jù)的 id 也是常見(jiàn)的業(yè)務(wù)需求。

PDO 提供了一個(gè)簡(jiǎn)單的獲取最后插入行的 ID 的方法 PDO::lastInsertId() 供我們使用。

基類(lèi)添加 insertGetLastId() 方法:

public function insertGetLastId(array $data)
{
    $this->insert($data);

    return $this->_pdo->lastInsertId();
}

測(cè)試:

$insert_data = [
    "username" => "jack",
    "age"      => 18,
];

$lastId = $driver->table("test_table")->insertGetLastId($insert_data);

個(gè)體差異

然而,上述的 insertGetLastId() 方法在 PostgreSql 中并不奏效。PostgreSql 中,使用 PDO::lastInsertId() 獲取結(jié)果需要傳入正確的自增序列名 (PostgreSQL 中創(chuàng)建表時(shí),如果使用 serial 類(lèi)型,默認(rèn)生成的自增序列名為:表名 + + 字段名 + + seq)。【1】

但是這個(gè)方式并不好用,因?yàn)樵L問(wèn) insertGetLastId() 方法時(shí)必須手動(dòng)傳入這個(gè)序列名稱(chēng),這樣 insertGetLastId() 方法對(duì)底層的依賴(lài)嚴(yán)重,比如當(dāng)?shù)讓域?qū)動(dòng)從 postgresql 換到 mysql 時(shí),需要更改上層應(yīng)用。而我們希望無(wú)論是 mysql 還是 postgresql,上層應(yīng)用調(diào)用 insertGetLastId() 方法時(shí)是無(wú)差別的,即底層對(duì)上層透明。

為了解決這個(gè)問(wèn)題,就需要用到 postgresql 的 returning 語(yǔ)法了。postgresql 中 insert、update 和 delete 操作都有一個(gè)可選的 returning 子句,可以指定最后執(zhí)行的字段進(jìn)行返回,返回的數(shù)據(jù)可以像 select 一樣取結(jié)果。【2】

對(duì)于我們返回最后插入行的 ID 的需求,只需 returning id 就好。

當(dāng)然,基類(lèi)的 insertGetLastId() 方法對(duì)于 postgresql 而言已經(jīng)無(wú)效了,我們?cè)?Pgsql 驅(qū)動(dòng)類(lèi)中重寫(xiě) insertGetLastId() 方法:

public function insertGetLastId(array $data)
{
    // 構(gòu)建語(yǔ)句字符串、綁定數(shù)據(jù)
    $field_str = "";
    $value_str = "";
    foreach ($data as $key => $value) {
        $field_str .= " ".self::_wrapRow($key).",";
        $plh = self::_getPlh();
        $this->_bind_params[$plh] = $value;
        $value_str .= " ".$plh.",";
    }

    $field_str = rtrim($field_str, ",");
    $value_str = rtrim($value_str, ",");
    // 使用 returning 子句返回 id
    $this->_insert_str = " (".$field_str.") VALUES (".$value_str.") RETURNING id ";
    // execute
    $this->_buildInsert();
    $this->_execute();
    // 使用 returning 子句后,可以像使用 SELECT 一樣獲取一個(gè) returning 指定字段的結(jié)果集。 
    $result = $this->_pdoSt->fetch(PDO::FETCH_ASSOC);
    // 返回 id
    return $result["id"];
}

OK,我們?cè)賮?lái)測(cè)試看看,是不是就好用了呢?

update

做完 insert,update 就很簡(jiǎn)單了,不同的是為了防止全局更新的失誤發(fā)生,update 構(gòu)造時(shí)強(qiáng)行要求使用 where 子句。

同樣的,添加 _update_str 屬性,修改 _reset() 函數(shù):

protected $_update_str = "";

...

protected function _reset()
{
    $this->_table = "";
    $this->_prepare_sql = "";
    $this->_cols_str = " * ";
    $this->_where_str = "";
    $this->_orderby_str = "";
    $this->_groupby_str = "";
    $this->_having_str = "";
    $this->_join_str = "";
    $this->_limit_str = "";
    $this->_insert_str = "";
    $this->_update_str = "";
    $this->_bind_params = [];
}

構(gòu)造 update 語(yǔ)句的方法:

protected function _buildUpdate()
{
    $this->_prepare_sql = "UPDATE ".$this->_table.$this->_update_str.$this->_where_str;
}

基類(lèi)中添加 update() 方法:

public function update(array $data)
{
    // 檢測(cè)有沒(méi)有設(shè)置 where 子句
    if(empty($this->_where_str)) {
        throw new InvalidArgumentException("Need where condition");
    }
    // 構(gòu)建語(yǔ)句、參數(shù)綁定
    $this->_update_str = " SET ";
    foreach ($data as $key => $value) {
        $plh = self::_getPlh();
        $this->_bind_params[$plh] = $value;
        $this->_update_str .= " ".self::_wrapRow($key)." = ".$plh.",";
    }

    $this->_update_str = rtrim($this->_update_str, ",");

    $this->_buildUpdate();
    $this->_execute();
    // 返回影響的行數(shù)
    return $this->_pdoSt->rowCount();
}

更新數(shù)據(jù)示例:

$update_data = [
    "username" => "lucy",
    "age"      => 22,
];

$results = $driver->table("test_table")
            ->where("username", "jack")
            ->update($update_data);
delete

相比 insert、update,delete 語(yǔ)句更為簡(jiǎn)單,只需 where 子句即可。和 update 一樣,需要防止誤操作刪除所有數(shù)據(jù)。

構(gòu)造 delete 語(yǔ)句的方法:

protected function _buildDelete()
{
    $this->_prepare_sql = "DELETE FROM ".$this->_table.$this->_where_str;
}

基類(lèi)中添加 delete() 方法:

public function delete()
{
    // 檢測(cè)有沒(méi)有設(shè)置 where 子句
    if(empty($this->_where_str)) {
        throw new InvalidArgumentException("Need where condition");
    }

    $this->_buildDelete();
    $this->_execute();

    return $this->_pdoSt->rowCount();
}

刪除數(shù)據(jù)示例:

$results = $driver->table("test_table")
            ->where("age", 18)
            ->delete();
事務(wù)

既然有了 DML 操作,那么就少不了事務(wù)。對(duì)于事務(wù),我們可以直接使用 PDO 提供的 PDO::beginTransaction()、PDO::commit()、PDO::rollBack()、PDO::inTransaction() 方法來(lái)實(shí)現(xiàn)。

基類(lèi)添加 beginTrans() 方法:

// 開(kāi)始事務(wù)
public function beginTrans()
{
    try {
        return $this->_pdo->beginTransaction();
    } catch (PDOException $e) {
        // 斷線重連
        if ($this->_isTimeout($e)) {

            $this->_closeConnection();
            $this->_connect();

            try {
                return $this->_pdo->beginTransaction();
            } catch (PDOException $e) {
                throw $e;
            }

        } else {
            throw $e;
        }
    }
}
注:因?yàn)?PDO::beginTransaction() 也是和 PDO::prepare() 一樣會(huì)連接數(shù)據(jù)庫(kù)的方法,所以需要做斷線重連的操作。

commitTrans() 方法:

// 提交事務(wù)
public function commitTrans()
{
    return $this->_pdo->commit(); 
}

rollBackTrans() 方法:

// 回滾事務(wù)
public function rollBackTrans()
{
    if ($this->_pdo->inTransaction()) {
        // 如果已經(jīng)開(kāi)始了事務(wù),則運(yùn)行回滾操作
        return $this->_pdo->rollBack();
    }
}

事務(wù)使用示例:

// 注冊(cè)事務(wù)
$driver->beginTrans();
$results = $driver->table("test_table")
            ->where("age", 18)
            ->delete();
$driver->commitTrans(); // 確認(rèn)刪除

// 回滾事務(wù)
$driver->beginTrans();
$results = $driver->table("test_table")
            ->where("age", 18)
            ->delete();
$driver->rollBackTrans(); // 撤銷(xiāo)刪除
參考

【1】PHP Manual - PDO::lastInsertId

【2】PostgreSQL Documentation - Returning Data From Modified Rows

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/30824.html

相關(guān)文章

  • 寫(xiě)一個(gè)特殊查詢(xún)構(gòu)造器 - (前言)

    摘要:而在項(xiàng)目開(kāi)發(fā)中,我們想要的是一個(gè)更好用的可維護(hù)的工具,此時(shí),對(duì)代碼的封裝模塊化就顯得尤為重要,于是出現(xiàn)了兩種方案查詢(xún)構(gòu)造器,對(duì)象關(guān)系映射。典型環(huán)境下按照一般的查詢(xún)構(gòu)造器處理就行。 文章目錄 寫(xiě)一個(gè)特殊的查詢(xún)構(gòu)造器 - (前言) 寫(xiě)一個(gè)特殊的查詢(xún)構(gòu)造器 - (一、程序結(jié)構(gòu),基礎(chǔ)封裝) 寫(xiě)一個(gè)特殊的查詢(xún)構(gòu)造器 - (二、第一條語(yǔ)句) 寫(xiě)一個(gè)特殊的查詢(xún)構(gòu)造器 - (三、條件查詢(xún)) 寫(xiě)一個(gè)特殊...

    GitChat 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<