数据库

大多数Web应用程序,其实都是围绕着数据库这个核心组件开发的。这里我们介绍Laravel中,如何使用MySQL和Redis这两种常见的关系型数据库和键值对数据库。

除此之外,使用Laravel操作关系型数据库时,还可以使用EloquentORM,有关内容将在后续章节介绍。

数据库配置

Laravel中,所有数据库配置内容都存储在config/database.php中。默认情况下,Laravel支持MySQLSqlitePostgreSQLSQL Server这四种关系型数据库。

'connections' => [
    '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'),
        ]) : [],
    ],
    ...
],

注意prefix,它可以用来配置数据库的表前缀。

配置字段都比较好理解,这里就不多说了。注意,实际开发中,开发、测试、生产环境经常使用不同的数据库,这里我们最好通过env()来进行配置。

'redis' => [

    'client' => env('REDIS_CLIENT', 'phpredis'),

    'options' => [
        'cluster' => env('REDIS_CLUSTER', 'redis'),
        'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
    ],

    'default' => [
        'url' => env('REDIS_URL'),
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', '6379'),
        'database' => env('REDIS_DB', '0'),
    ],

    'cache' => [
        'url' => env('REDIS_URL'),
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', '6379'),
        'database' => env('REDIS_CACHE_DB', '1'),
    ],

],

redis配置中,注意client配置,这里我们推荐使用php_redis这个PHP扩展来连接redis,而不是predis

关系型数据库执行SQL语句

执行SQL是操作数据库最简单也是最强大的方式,某些框架比如Django,对ORM进行了深度耦合的封装,使用原生SQL都很困难,其实是本末倒置的。

而Laravel中,使用原生SQL非常简单。读取返回结果也很容易,和原生PHP相同,使用关联数组即可。

SQL查询

下面代码使用SELECT语句查询数据库,并返回一个Json内容。

public function user(Request $request)
{
    $username = $request->input('username');
    if (!$username) {
        abort(400);
    }
    $users = DB::select('select * from users where user_name=?', [$username]);
    return response()->json($users);
}

如果SQL拼接的参数太多,可以使用命名绑定的方式。

$users = DB::select('select * from users where user_name=:username', ['username' => $username]);

SQL增删改

除了SELECT语句,Laravel还提供了DB::insert()DB::update()DB::delete()DB::statement()来执行插入、更新、删除和通用语句。下面是一个插入数据的例子。

public function add_user(Request $request)
{
    $username = $request->input('username');
    $password = $request->input('password');
    if (!$username || !$password) {
        abort(400);
    }
    DB::insert('insert into users (user_name, password) values (?,?)', [$username, $password]);
    return response()->json(['msg' => '操作成功']);
}

SQL事务

DB::transaction()能够创建事务,事务中包含多条语句,如果一条执行失败则事务回滚。

DB::transaction(function () {
    DB::table('users')->update(['votes' => 1]);
    DB::table('posts')->delete();
});

Redis存取

下面代码中,实现了查询时先查询Redis,如果没有数据,再查询数据库,并将内容存入Redis中,这样一个简单的缓存逻辑。

public function user(Request $request)
{
    $username = $request->input('username');
    if (!$username) {
        abort(400);
    }

    $user = Redis::get('userCache:'.$username);
    if (!$user) {
        $users = DB::select('select * from users where user_name=:username', ['username' => $username]);
        if (count($users) == 1) {
            $user = $users[0];
            Redis::set('userCache:'.$username, json_encode($user));
            return response()->json(['loadFrom' => 'db', 'user' => $user]);
        } else {
            abort(404);
        }
    }
    return response()->json(['loadFrom' => 'cache', 'user' => json_decode($user)]);
}

代码其实很好理解,这里注意Redis存取时,我们数据库的查询结果是关联数组,而Redis中的内容需要我们对其进行序列化(转为Json),因此这里使用json_decode()json_encode()两个函数来进行处理。

数据库迁移

Laravel提供了数据库迁移功能,我们可以通过编写数据库无关的迁移脚本,来实现数据库表定义的版本控制。

注:Laravel的数据库迁移功能,比Django可差太远了,Laravel中我们必须手动编写迁移脚本(Django能够根据数据模型字段变更自动维护迁移脚本)。相比Django的局限性大,和直接维护SQL脚本的使用不便,Laravel兼具了局限性大和使用不便两个缺点。

创建新的数据表迁移

我们可以使用artisan make:migration命令创建迁移脚本。

php artisan make:migration create_customer_table --create=customers

其中,create_customer_table是我们定义的脚本名,--create代表该迁移脚本新建数据表,customers是表名。

自动生成的迁移脚本代码框架:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateCustomerTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('customers', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('customers');
    }
}

代码中,up()方法表示运行迁移脚本时,需要进行的操作逻辑,而down()则相反,是回滚该迁移操作的逻辑。

Schema::create()方法中,第一个参数为表名,第二个参数为建表的字段定义操作。

使用artisan migrate命令,可以执行迁移。

php artisan migrate

修改表结构迁移

artisan make:migration中,使用--table参数,能够生成修改数据表结构的迁移脚本代码框架。

php artisan make:migration add_column_to_customer_table --table=customers

自动生成的迁移脚本代码框架:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddColumnToCustomerTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('customers', function (Blueprint $table) {
            //
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('customers', function (Blueprint $table) {
            //
        });
    }
}

我们在其中编写增加数据列等逻辑即可。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。