数据库
大多数Web应用程序,其实都是围绕着数据库这个核心组件开发的。这里我们介绍Laravel中,如何使用MySQL和Redis这两种常见的关系型数据库和键值对数据库。
除此之外,使用Laravel操作关系型数据库时,还可以使用EloquentORM,有关内容将在后续章节介绍。
数据库配置
Laravel中,所有数据库配置内容都存储在config/database.php中。默认情况下,Laravel支持MySQL、Sqlite、PostgreSQL、SQL 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) {
//
});
}
}
我们在其中编写增加数据列等逻辑即可。