免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開(kāi)通VIP
【Laravel系列4.1】連接數(shù)據(jù)庫(kù)與原生查詢

連接數(shù)據(jù)庫(kù)與原生查詢

在 PHP 的學(xué)習(xí)中,數(shù)據(jù)庫(kù),也就是 MySQL 就像它的親兄弟一樣,永遠(yuǎn)沒(méi)法分家。同理,在框架中,數(shù)據(jù)庫(kù)相關(guān)的功能也是所有框架必備的內(nèi)容。從最早期我們會(huì)自己封裝一個(gè) MyDB 這種的數(shù)據(jù)庫(kù)操作文件,到框架提供一套完整的 CRUD 類,再到現(xiàn)代化的框架中的 ORM ,其基礎(chǔ)都是在變著花樣的完成數(shù)據(jù)操作。當(dāng)然,本身數(shù)據(jù)庫(kù)也是 WEB 開(kāi)發(fā)中的核心,所以一個(gè)框架對(duì)于數(shù)據(jù)庫(kù)的支持的好壞,也會(huì)影響到它的普及。

Laravel 框架中的 DB 和 ORM 是兩個(gè)不同的組件,關(guān)于 ORM 的概念,我們也將在相關(guān)的學(xué)習(xí)中了解到,但是現(xiàn)在我們先從簡(jiǎn)單的普通查詢學(xué)起。今天的內(nèi)容比較簡(jiǎn)單,我們要先能連接數(shù)據(jù)庫(kù),然后再能使用原始 SQL 語(yǔ)句的方式來(lái)對(duì)數(shù)據(jù)進(jìn)行操作。

連接數(shù)據(jù)庫(kù)配置

首先我們可以看下配置文件,在 Laravel 程序的 config 目錄下,有一個(gè) database.php 文件,其中有關(guān)于數(shù)據(jù)庫(kù)的連接配置信息。

// ………………
// ………………
'mysql' => [
    'driver' => 'mysql',
    'url' => env('DATABASE_URL'),
    'host' => env('DB_HOST''127.0.0.1'),
    'port' => env('DB_PORT''3306'),
    'database' => env('DB_DATABASE''forge'),
    'username' => env('DB_USERNAME''forge'),
    'password' => env('DB_PASSWORD'''),
    'unix_socket' => env('DB_SOCKET'''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'prefix_indexes' => true,
    'strict' => true,
    'engine' => null,
    'options' => extension_loaded('pdo_mysql') ? array_filter([
        PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
    ]) : [],
],
// ………………
// ………………

在這個(gè)配置文件中,我們還能看到許多其它數(shù)據(jù)庫(kù)的配置,不過(guò),今天我們的重點(diǎn)還是在 mysql 這個(gè)配置中。除了這個(gè)默認(rèn)配置外,我們還可以再添加多個(gè)連接配置,只要復(fù)制這個(gè) mysql 的配置,然后改名就可以了。從 options 這個(gè)參數(shù)里面,我們可以看出,Laravel 默認(rèn)使用的是 PDO 連接的數(shù)據(jù)庫(kù),我也沒(méi)有研究在 Laravel 中如何使用 mysqli 進(jìn)行連接,因?yàn)?PDO 確實(shí)已經(jīng)是事實(shí)的連庫(kù)標(biāo)準(zhǔn)了,完全沒(méi)必要另辟蹊徑。

在這個(gè) mysql 的配置中,我們會(huì)發(fā)現(xiàn)很多 env() 函數(shù)調(diào)用的信息。這個(gè)函數(shù)是用于讀取 .env 文件中所寫的配置信息的。它有兩個(gè)參數(shù),一個(gè)是指定的配置文件中的鍵名,一個(gè)是如果沒(méi)有找到的話,就會(huì)給一個(gè)默認(rèn)值。關(guān)于這個(gè)函數(shù),還記得我們?cè)谥熬鸵呀?jīng)講過(guò)了。比如現(xiàn)在在我的本地測(cè)試環(huán)境中,連接數(shù)據(jù)庫(kù)就是使用 .env 中如下的配置:

// ………………
// ………………
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=
// ………………
// ………………

我的本地?cái)?shù)據(jù)庫(kù)不需要密碼,連接也不需要做其它的操作,所以可以非常簡(jiǎn)單地這樣配置一下就可以了。這樣,線上、測(cè)試和本地環(huán)境,就不會(huì)互相沖突,也不需要我們?cè)诟鱾€(gè)環(huán)境中進(jìn)行各種 hosts 修改。

原生查詢

接下來(lái),我們就學(xué)習(xí)怎么使用原生 SQL 語(yǔ)句進(jìn)行數(shù)據(jù)庫(kù)操作。這種操作其實(shí)就像是 Laravel 為我們封裝好了 PDO 的調(diào)用,也就是像我們?cè)诤茉缜白约悍庋b的那種數(shù)據(jù)庫(kù)調(diào)用類一樣,非常簡(jiǎn)單方便。不過(guò)首先,我們要建立一張測(cè)試表,之后我們將對(duì)這張表進(jìn)行 CRUD 操作。

CREATE TABLE `raw_test` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
  `sex` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

目前這個(gè)表是沒(méi)有數(shù)據(jù)的,所以我們需要先添加幾條數(shù)據(jù)。

Route::get('rawdb/test/insert'function () {
    $data = [
        'Peter' => 1,
        'Tom'   => 1,
        'Susan' => 2,
        'Mary'  => 2,
        'Jim'   => 1,
    ];
    foreach ($data as $k => $v) {
        \Illuminate\Support\Facades\DB::insert('insert into raw_test (name, sex) values (?, ?)', [$k, $v]);
        $insertId = DB::getPdo()->lastInsertId();
        echo $insertId, '<br/>';
    }
});

因?yàn)槭菧y(cè)試數(shù)據(jù)庫(kù)的操作,所以就直接在路由中寫代碼了,在實(shí)際的業(yè)務(wù)開(kāi)發(fā)中,大家可不要這么做哦。在代碼中,我們通過(guò) DB 這個(gè)門面類的 insert() 方法,就可以實(shí)現(xiàn)原生語(yǔ)句的增加操作。對(duì)于路由來(lái)說(shuō),其實(shí)我們不用寫完全限定命名空間的類名,直接寫個(gè) DB 也是可以的。不過(guò)在這里為了突顯出我們是調(diào)用了這個(gè)門面類,所以才寫了這個(gè)完全限定名字稱的類名。

看這個(gè) insert() 函數(shù)的參數(shù)寫法,是不是和 PDO 的預(yù)處理語(yǔ)句的寫法很像?語(yǔ)句里面使用占位符,后面一個(gè)數(shù)組里面?zhèn)鬟f參數(shù)。沒(méi)錯(cuò),前面也說(shuō)過(guò),本身 Laravel 的數(shù)據(jù)庫(kù)操作就是使用的 PDO 的,不記得的小伙伴可以移步 【PHP中的PDO操作學(xué)習(xí)(四)查詢結(jié)構(gòu)集】https://mp.weixin.qq.com/s/dv-lnEGV0JlGsjy4rl_jkw 查看 PDO 相關(guān)的基礎(chǔ)知識(shí)。我們也可以使用 :xxx 這樣的占位符,這個(gè)大家自己去試下吧。

注意,insert() 方法返回的結(jié)果是一個(gè)布爾值,也就是添加操作的成功失敗情況,如果我們想獲取新增加的數(shù)據(jù)的 id ,需要使用 DB::getPdo()->lastInsertId(); 這條語(yǔ)句才可以獲取到。

做完新增了,我們?cè)賮?lái)試下修改和刪除。

Route::get('rawdb/test/update'function () {
    $data = [
        'name' => request()->name,
        'sex' => request()->sex,
        'id' => request()->id
    ];

    if($data['id'] < 1 || !$data['name'] || !in_array($data['sex'], [12])){
        echo '參數(shù)錯(cuò)誤';
    }

    \Illuminate\Support\Facades\DB::update('update raw_test set name=:name,sex =:sex where id = :id', $data);

    echo '修改成功';
});

Route::get('rawdb/test/delete'function () {

    $id = request()->id;
    if($id < 1){
        echo '參數(shù)錯(cuò)誤';
    }

    \Illuminate\Support\Facades\DB::delete('delete from raw_test where id = :id', ['id'=>$id]);

    echo '刪除成功';
});

代碼很簡(jiǎn)單,就不多做解釋了,不過(guò)這里大家能看到的一點(diǎn)是,我們?cè)谛薷暮蛣h除操作中,綁定數(shù)據(jù)使用的是 :xxx 這種方式哦!

在學(xué)習(xí) PDO 的時(shí)候,我們知道,預(yù)處理語(yǔ)句的執(zhí)行就是先 prepare() 再 execute() 一下就可以了,特別是增刪改的操作是非常類似的,那么我們?cè)谶@里是不是可以在 insert() 方法里面執(zhí)行一個(gè)修改或者刪除語(yǔ)句呢?我們先嘗試一下。

Route::get('rawdb/test/delete2'function () {

    $id = request()->id;
    if($id < 1){
        echo '參數(shù)錯(cuò)誤';
    }

    \Illuminate\Support\Facades\DB::insert('delete from raw_test where id = :id', ['id'=>$id]);

    echo '刪除成功';
});

嗯,你猜對(duì)了,我們的執(zhí)行成功了,使用 insert() 方法,但是里面的語(yǔ)句是一條 delete 語(yǔ)句,是可以執(zhí)行成功的。這就很詭異了吧,為什么要這樣呢?直接提供一個(gè)方法讓我們進(jìn)行操作就好了嘛。其實(shí),這也正是 Laravel 優(yōu)雅的由來(lái)。為了更好地區(qū)分度和代碼的清晰。我們?cè)趯忛啿榭创a時(shí),按照標(biāo)準(zhǔn)的規(guī)范寫,不需要詳細(xì)的看語(yǔ)句,就可以通過(guò)方法名快速地知道這段數(shù)據(jù)庫(kù)操作是要干什么,這不是非常好的一件事嘛。

在 laravel/framework/src/Illuminate/Database/Connection.php 文件中,我們可以找到 insert() 、update()、delete() 這些方法,其中 insert() 會(huì)繼續(xù)調(diào)用一個(gè) statement() 方法,而 update() 和 delete() 會(huì)調(diào)用 affectingStatement() 方法。仔細(xì)查看這兩個(gè)方法,你會(huì)發(fā)現(xiàn)只有返回結(jié)果的地方是稍有不同的,statement() 返回的是布爾值,而 affectingStatement() 返回的是影響行數(shù)。

public function statement($query, $bindings = [])
{
    return $this->run($query, $bindings, function ($query, $bindings) {
        if ($this->pretending()) {
            return true;
        }

        $statement = $this->getPdo()->prepare($query);

        $this->bindValues($statement, $this->prepareBindings($bindings));

        $this->recordsHaveBeenModified();

        return $statement->execute();
    });
}

public function affectingStatement($query, $bindings = [])
{
    return $this->run($query, $bindings, function ($query, $bindings) {
        if ($this->pretending()) {
            return 0;
        }

        $statement = $this->getPdo()->prepare($query);

        $this->bindValues($statement, $this->prepareBindings($bindings));

        $statement->execute();

        $this->recordsHaveBeenModified(
            ($count = $statement->rowCount()) > 0
        );

        return $count;
    });
}

看這個(gè)源代碼,是不是馬上就能看出來(lái),$statment 就是一個(gè) PDO 的預(yù)編譯對(duì)象 PDOStatment ,后面的操作其實(shí)就是 PDO 的操作了。

好了,最后還差一個(gè)查詢,查詢就更簡(jiǎn)單了,我們直接測(cè)試一下下面的代碼就好了。查閱的源代碼也在上面的那個(gè)文件中哦,大家可以自己去看一看,內(nèi)容和上面的那兩個(gè) statment 方法里面的東西都差不多,也是在返回結(jié)果的地方會(huì)有些區(qū)別。

Route::get('rawdb/test/show'function () {
    dd(\Illuminate\Support\Facades\DB::select("select * from raw_test"));
});

dd() 這個(gè)方法貌似前面一直沒(méi)講過(guò),它是一個(gè)可以方便快速調(diào)試的函數(shù)。大家試試就知道啦!

連接另外一個(gè)數(shù)據(jù)庫(kù)

上面通過(guò)使用原生語(yǔ)句的方式我們可以方便地進(jìn)行增、刪、改、查操作了,也就是常說(shuō)的 CRUD 。接下來(lái)我們來(lái)看看怎樣連接其它的數(shù)據(jù)庫(kù)。

首先,我們新建一個(gè)數(shù)據(jù)庫(kù),就叫 laravel8 好了,并且同樣的建立一個(gè) raw_test 表,然后就是在 .env 中配置這個(gè)數(shù)據(jù)庫(kù)的連接信息。

DB_CONNECTION_LARAVEL8=mysql
DB_HOST_LARAVEL8=127.0.0.1
DB_PORT_LARAVEL8=3306
DB_DATABASE_LARAVEL8=laravel8
DB_USERNAME_LARAVEL8=root
DB_PASSWORD_LARAVEL8=

其實(shí)就是復(fù)制了一下基礎(chǔ)的那個(gè) DB 配置,然后改了下配置名稱以及連接的數(shù)據(jù)庫(kù)名稱。接下來(lái),修改 config/database.php 文件,增加一個(gè)連接配置。

'laravel8' => [
    'driver' => 'mysql',
    'url' => env('DATABASE_URL_LARAVEL8'),
    'host' => env('DB_HOST_LARAVEL8''127.0.0.1'),
    'port' => env('DB_PORT_LARAVEL8''3306'),
    'database' => env('DB_DATABASE_LARAVEL8''forge'),
    'username' => env('DB_USERNAME_LARAVEL8''forge'),
    'password' => env('DB_PASSWORD_LARAVEL8'''),
    'unix_socket' => env('DB_SOCKET_LARAVEL8'''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'prefix_indexes' => true,
    'strict' => true,
    'engine' => null,
    'options' => extension_loaded('pdo_mysql') ? array_filter([
        PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
    ]) : [],
],

同樣的,我們也是復(fù)制了一下 mysql 那個(gè)配置,然后修改相關(guān)的名稱以及 env() 讀取字段的名稱。通過(guò)上面兩步,我們的配置就完成了,是不是非常簡(jiǎn)單,接下來(lái)就是在代碼中如何使用。

Route::get('rawdb/laravel8/test'function () {
    \Illuminate\Support\Facades\DB::connection('laravel8')->insert('insert into raw_test (name, sex) values (?, ?)', ['Sam'1]);
    dd(\Illuminate\Support\Facades\DB::connection('laravel8')->select("select * from raw_test"));
});

注意看代碼,其實(shí)我們只是多使用了一個(gè) connection() 方法。它的作用就是找到指定的連接,在默認(rèn)情況下,Laravel 框架會(huì)去找 mysql 這個(gè)配置,如果我們需要操作其它數(shù)據(jù)庫(kù)的話,就需要通過(guò) connection() 來(lái)指定要連接的數(shù)據(jù)庫(kù)。是不是非常簡(jiǎn)單明了,配置過(guò)程也很輕松方便。

底層的 PDO 在哪里?

在使用 DB 門面的情況下,我們會(huì)通過(guò)服務(wù)容器注冊(cè)門面并實(shí)例化一個(gè) laravel/framework/src/Illuminate/Database/DatabaseManager.php 對(duì)象,它的 connection() 方法會(huì)讀取配置信息,然后通過(guò) makeConnection() 方法去創(chuàng)建連接。

protected function makeConnection($name)
{
    $config = $this->configuration($name);

    if (isset($this->extensions[$name])) {
        return call_user_func($this->extensions[$name], $config, $name);
    }

    if (isset($this->extensions[$driver = $config['driver']])) {
        return call_user_func($this->extensions[$driver], $config, $name);
    }

    return $this->factory->make($config, $name);
}

看到 factory 了吧,能起這個(gè)名字的基本上多少都會(huì)和工廠沾邊,不過(guò)在這里,它指向的是一個(gè)明確的 laravel/framework/src/Illuminate/Database/Connectors/ConnectionFactory.php 對(duì)象。通過(guò) ConnectionFactory 里面的 make() 方法,根據(jù)情況調(diào)用不同的連接創(chuàng)建方法,一路向下,我們進(jìn)入到 createSingleConnection() 方法中,繼續(xù)前進(jìn),進(jìn)入到 createPdoResolverWithHosts() 方法。

protected function createPdoResolverWithHosts(array $config)
{
    return function () use ($config) {
        foreach (Arr::shuffle($hosts = $this->parseHosts($config)) as $key => $host) {
            $config['host'] = $host;

            try {
                return $this->createConnector($config)->connect($config);
            } catch (PDOException $e) {
                continue;
            }
        }

        throw $e;
    };
}

public function createConnector(array $config)
{
    if (! isset($config['driver'])) {
        throw new InvalidArgumentException('A driver must be specified.');
    }

    if ($this->container->bound($key = "db.connector.{$config['driver']}")) {
        return $this->container->make($key);
    }

    switch ($config['driver']) {
        case 'mysql':
            return new MySqlConnector;
        case 'pgsql':
            return new PostgresConnector;
        case 'sqlite':
            return new SQLiteConnector;
        case 'sqlsrv':
            return new SqlServerConnector;
    }

    throw new InvalidArgumentException("Unsupported driver [{$config['driver']}].");
}

注意這個(gè) createConnector() 方法,它是一個(gè) 簡(jiǎn)單工廠 模式的應(yīng)用,通過(guò)它,我們獲得了配置文件中相關(guān)配置的連接對(duì)象,比如 mysql 數(shù)據(jù)庫(kù)的返回的就是 MySqlConnector 這個(gè)對(duì)象。接下來(lái),調(diào)用它的 connect() 方法,這時(shí)我們會(huì)進(jìn)入 laravel/framework/src/Illuminate/Database/Connectors/MySqlConnector.php 文件。

public function connect(array $config)
{
    $dsn = $this->getDsn($config);

    $options = $this->getOptions($config);

    $connection = $this->createConnection($dsn, $config, $options);

    if (! empty($config['database'])) {
        $connection->exec("use `{$config['database']}`;");
    }

    $this->configureIsolationLevel($connection, $config);

    $this->configureEncoding($connection, $config);


    $this->setModes($connection, $config);

    return $connection;
}

在這里,我們需要注意的是 createConnection() 方法,在這個(gè)方法中會(huì)繼續(xù)調(diào)用 createPdoConnection() 這個(gè)方法。

protected function createPdoConnection($dsn, $username, $password, $options)
{
    if (class_exists(PDOConnection::class) && ! $this->isPersistentConnection($options)) {
        return new PDOConnection($dsn, $username, $password, $options);
    }

    return new PDO($dsn, $username, $password, $options);
}

Oh,My God!我們總算在 createPdoConnection() 見(jiàn)到了 PDO 的真容,這一路走來(lái)真的是跋山涉水呀!不過(guò),總算我們還是不負(fù)所望地找到了 PDO 到底是在哪里創(chuàng)建的。在這其中,我們還看到了 工廠模式 在這其中發(fā)揮的作用。也算是取到了一部分的真經(jīng),大家都要為自己鼓掌哦!

總結(jié)

數(shù)據(jù)庫(kù)上手就是一堆源碼,不過(guò)這也讓我們搞清楚了 Laravel 在底層是如何去創(chuàng)建一個(gè) PDO 對(duì)象的。而且我們會(huì)發(fā)現(xiàn),Laravel 只能使用 PDO ,無(wú)法使用 MySQLi 來(lái)進(jìn)行數(shù)據(jù)庫(kù)操作。當(dāng)然,這也是為了框架的通用性,因?yàn)?PDO 也是通用的,在工廠中,我們可以看到 Postgres、SQLite、SQLServer 的連接器,如果使用 MySQLi 的話,可就沒(méi)辦法支持這些數(shù)據(jù)庫(kù)了哦。

參考文檔:

https://learnku.com/docs/laravel/8.x/database/9400

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Laravel入門教程-搭建一個(gè)簡(jiǎn)單的網(wǎng)站
PHP中如何連接數(shù)據(jù)庫(kù)
redmine在windows上安裝初體驗(yàn)
puppet-dashboard配置
在 Ubuntu/Debian 上安裝 Huginn
mysql 創(chuàng)建刪除數(shù)據(jù)庫(kù)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服