配置

数据库的配置文件放置在 config/database.php 文件中,你可以在此定义所有的数据库连接,并指定默认使用的连接。此文件内提供了大部分 Laravel 能支持的数据库配置示例。

基本配置

**v

  1. DB_CONNECTION=mysql
  2. DB_HOST=127.0.0.1
  3. DB_PORT=3306
  4. DB_DATABASE=laravel
  5. DB_USERNAME=root
  6. DB_PASSWORD=root

config/database.php

// 选择链接的数据库
'default' => env('DB_CONNECTION', 'mysql'),
// MySQL配置
'mysql' => [
  'driver' => 'mysql',
  'url' => env('DATABASE_URL'),
  'host' => env('DB_HOST', '127.0.0.1'),
  'port' => env('DB_PORT', '3306'),
  'database' => env('DB_DATABASE', 'laravel'),
  'username' => env('DB_USERNAME', 'root'),
  'password' => env('DB_PASSWORD', 'root'),
  'unix_socket' => env('DB_SOCKET', ''),
  'charset' => 'utf8mb4',
  'collation' => 'utf8mb4_unicode_ci',
  'prefix' => '',
];

URLs式的配置:
通常,数据库连接使用多个配置值,例如 host , database , username , password 等。这些配置值中的每一个都有其相应的环境变量。这意味着在生产服务器上配置数据库连接信息时,需要管理多个环境变量。
一些托管数据库提供程序(如 heroku )提供单个数据库「URL」,该 url 在单个字符串中包含数据库的所有连接信息。示例数据库 URL 可能如下所示:

mysql://root:password@127.0.0.1/forge?charset=UTF‐8

这些 url 通常遵循标准模式约定:

driver://username:password@host:port/database?options

读写分离配置

'mysql' => [
  'read' => [
    'host' => [
      '192.168.1.1',
      '196.168.1.2',
    ],
  ],
  'write' => [
    'host' => [
      '196.168.1.3',
    ],
  ],
  'sticky' => true,
  'driver' => 'mysql',
  'database' => 'database',
  'username' => 'root',
  'password' => '',
  'charset' => 'utf8mb4',
  'collation' => 'utf8mb4_unicode_ci',
  'prefix' => '',
]

sticky 是一个 可选值,它可用于立即读取在当前请求周期内已写入数据库的记录。若 sticky 选项被启用,并且当前请求周期内执行过 「写」 操作,那么任何 「读」 操作都将使用 「写」 连接。这样可确保同一个请求周期内写入的数据可以被立即读取到,从而避免主从延迟导致数据不一致的问题。不过是否启用它,取决于应用程序的需求。

数据库操作

据库连接

$users = DB::connection('foo')‐>select(...);
$pdo = DB::connection()‐>getPdo();

数据库事务

// 开启事务
DB::beginTransaction();
// 事务回滚
DB::rollBack();
// 提交事务
DB::commit();
DB::transaction(function () {
  DB::table('users')‐>update(['votes' => 1]);
  DB::table('posts')‐>delete();
});

transaction 方法接受一个可选的第二个参数 ,该参数用来表示事务发生死锁时重复执行的次数。一旦定义的次数尝试完毕,就会抛出一个异常

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

查询构造器

SQL监听:使用在AppServiceProvider中的boot方法中注入

DB::listen(function ($query) {
  echo $query‐>sql;
  // $query‐>bindings
  // $query‐>time
});

单表查询

<?php
  namespace App\Http\Controllers;
  use Illuminate\Support\Facades\DB;
  use App\Http\Controllers\Controller;
  class UserController extends Controller {
    /**
    * 显示所有应用程序的用户列表。
    ** @return Response 
    */
    public function index() {
      $users = DB::table('users')‐>get();
      return view('user.index', ['users' => $users]);
    }
  }

get 方法返回一个包含 Illuminate\Support\Collection 的结果,其中每个结果都是 PHP StdClass 对象的一个实例。可以访问字段作为对象的属性来访问每列的值:

foreach ($users as $user) { echo $user‐>name; }
$user = DB::table('users')‐>where('name', 'John')‐>first();
echo $user‐>name;
$email = DB::table('users')‐>where('name', 'John')‐>value('email')
$titles = DB::table('roles')‐>pluck('title');
foreach ($titles as $title) { echo $title; }
//name字段为键名
//title字段为键值
$roles = DB::table('roles')‐>pluck('title', 'name');
foreach ($roles as $name => $title) { echo $title; }
$users = DB::table('users')‐>where('votes', '=', 100)‐>get();
$users = DB::table('users') ‐>where('votes', '>=', 100) ‐>get();
$users = DB::table('users') ‐>where('votes', '<>', 100) ‐>get();
$users = DB::table('users') ‐>where('name', 'like', 'T%') ‐>get()
$users = DB::table('users')‐>where([ ['status', '=', '1'], ['subscribed', '<>', '1'], ])‐>get();
$users = DB::table('users') ‐>where('votes', '>', 100) ‐>orWhere('name', 'John') ‐>get();
$users = DB::table('users')
  ‐>where('name', '=', 'John')
  ‐>where(function ($query) {
    $query‐>where('votes', '>', 100)
      ‐>orWhere('title', '=', 'Admin');
  })‐>get();

//等价于
select * from users where name = 'John' and (votes > 100 or title = 'Admin')
$users = DB::table('users')
  ‐>whereExists(function ($query) {
    $query‐>select(DB::raw(1))
      ‐>from('orders')
      ‐>whereRaw('orders.user_id = users.id');
  })‐>get();

//等价于
select * from users where exists ( select 1 from orders where orders.user_id = users.id )
$users = DB::table('users') ‐>orderBy('name', 'desc') ‐>get()
//随机排序
$randomUser = DB::table('users') ‐>inRandomOrder() ‐>first();
$users = DB::table('users') ‐>groupBy('account_id') ‐>having('account_id', '>', 100) ‐>get();
$users = DB::table('users') ‐>offset(10) ‐>limit(5) ‐>get();
//跳过10行 限制5行
$users = DB::table('users')‐>skip(10)‐>take(5)‐>get();
//查询数量
$users = DB::table('users')‐>count();
//查询最大值
$price = DB::table('orders')‐>max('price');
//查询平均值
$price = DB::table('orders')‐>where('finalized', 1)‐>avg('price');

分块操作:如果你需要处理上千条数据库记录,你可以考虑使用 chunk 方法。该方法一次获取结果集的一小块,并将其传递给闭包 函数进行处理。该方法在 Artisan 命令 编写数千条处理数据的时候非常有用。

DB::table('city')‐>orderBy('city_id')‐>chunk(100, function ($citys) {
  foreach ($citys as $city) {
    echo $city‐>city_id.' name : '.$city‐>city_name.'<br>';
  }
});

连接查询

$users = DB::table('users')
  ‐>join('contacts', 'users.id', '=', 'contacts.user_id')
  ‐>join('orders', 'users.id', '=', 'orders.user_id')
  ‐>select('users.*', 'contacts.phone', 'orders.price')
  ‐>get();
$users = DB::table('users')
  ‐>leftJoin('posts', 'users.id', '=', 'posts.user_id')
  ‐>get();

$users = DB::table('users')
  ‐>rightJoin('posts', 'users.id', '=', 'posts.user_id')
  ‐>get()

你可以指定更高级的 join 语句。比如传递一个 闭包 作为 join 方法的第二个参数。此 闭包 接收一个 JoinClause 对象,从而指定 join 语句中指定的约束

DB::table('users')‐>join('contacts', function ($join) {
  $join‐>on('users.id', '=', 'contacts.user_id')‐>orOn(...);
})‐>get();

DB::table('users')‐>join('contacts', function ($join) {
  $join‐>on('users.id', '=', 'contacts.user_id')
    ‐>where('contacts.user_id', '>', 5);
})‐>get();

数据插入

DB::table('users')‐>insert( ['email' => 'john@example.com', 'votes' => 0] );
DB::table('users')‐>insert(
  [
    ['email' => 'taylor@example.com', 'votes' => 0],
    ['email' => 'dayle@example.com', 'votes' => 0]
  ]
);
DB::table('users')‐>insert(
  [
    ['email' => 'taylor@example.com', 'votes' => 0],
    ['email' => 'dayle@example.com', 'votes' => 0]
  ]
);
$id = DB::table('users')‐>insertGetId( ['email' => 'john@example.com', 'votes' => 0] );

数据更新

$affected = DB::table('users') ‐>where('id', 1) ‐>update(['votes' => 1]);
DB::table('users') ‐>updateOrInsert( ['email' => 'john@example.com', 'name' => 'John'], ['votes' => '2'] );
$affected = DB::table('users') ‐>where('id', 1) ‐>update(['options‐>enabled' => true]);
DB::table('users')‐>increment('votes'); DB::table('users')‐>increment('votes', 5); DB::table('users')‐>decrement('votes'); DB::table('users')‐>decrement('votes', 5);
//指定更新字段
DB::table('users')‐>increment('votes', 1, ['name' => 'John']);

数据删除

//删除表数据
DB::table('users')‐>delete();
//根据条件删除
DB::table('users')‐>where('votes', '>', 100)‐>delete();
//清空表
DB::table('users')‐>truncate();
//显示调试信息,然后停止执行请求
DB::table('users')‐>where('votes', '>', 100)‐>dd();
//显示调试信息,但是不会停止执行请求
DB::table('users')‐>where('votes', '>', 100)‐>dump();

数据库迁移

迁移就像是数据库的版本控制器,让你的团队更容易修改和共享程序的数据库结构。迁移通常配合 Laravel 的结构生成器,能更容易的生成应用程序的数据库结构。如果你曾经让一个团队成员在他本地的数据库结构中手动的添加了字段,那么你将面对解决数据库迁移的问题。
数据迁移的文件目录 :

  1. Migrations里面定义的是数据迁移的数据表
  2. Seeds 数据内容
  3. Factories 测试数据
    php artisan make:migration create_users_table ‐‐create=users # 创建数据表迁移
    php artisan make:migration add_votes_to_users_table ‐‐table=users # 更新数据表迁移
    
    一个迁移类包含两个方法: up 和 down 。 up 方法是用于新增数据库的数据表、字段或者索引的,而 down 方法应该与 up 方法的执行操作相反。
    <?php use Illuminate\Support\Facades\Schema;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Database\Migrations\Migration;
    class CreateFlightsTable extends Migration {
    /**
    * Run the migrations. 
    ** @return void
    */
    public function up() {
     Schema::create('flights', function (Blueprint $table) {
       $table‐>bigIncrements('id');
       $table‐>string('name');
       $table‐>string('airline');
       $table‐>timestamps();
     });
    }
    /*
    ** Reverse the migrations.
    ** @return void
    */
    public function down() {
     Schema::drop('flights');
    }
    }
    
    //普通执行迁移,一般会有提示
    php artisan migrate
    //强制执行迁移,不会有提示
    php artisan migrate ‐‐force
    
    php artisan migrate:rollback
    //可以回滚指定数量的迁移
    php artisan migrate:rollback ‐‐step=5
    //回滚所有迁移
    php artisan migrate:reset
    //回滚所有的迁移后执行 migrate 命令
    php artisan migrate:refresh
    //刷新数据库并执行数据库填充
    php artisan migrate:refresh ‐‐seed
    

    数据表

    Schema::create('users', function (Blueprint $table) {
    $table‐>bigIncrements('id');
    });
    
    if (Schema::hasTable('users')) { }
    if (Schema::hasColumn('users', 'email')) { }
    
    Schema::connection('foo')‐>create('users', function (Blueprint $table) {
    $table‐>bigIncrements('id');
    })
    
    //重命名
    Schema::rename($from, $to);
    //删除表
    Schema::drop('users');
    Schema::dropIfExists('users');
    
    在重命名数据表之前,应该验证表上的任何外键约束在迁移文件中是否具有确切的名称,而不是让 Laravel 按照约定来分配一个名称。否则,外键约束名将引用旧表名。
    Schema::table('users', function (Blueprint $table) {
    $table‐>bigIncrements('id'); //递增 ID(主键),相当于「UNSIGNED BIG INTEGER」
    $table‐>bigInteger('votes'); //相当于 BIGINT
    $table‐>binary('data'); //相当于 BLOB
    $table‐>boolean('confirmed'); //相当于 BOOLEAN
    $table‐>char('name', 100); //相当于带有长度的 CHAR
    $table‐>date('created_at'); //相当于 DATE
    $table‐>dateTime('created_at'); //相当于 DATETIME
    })
    
    Schema::table('users', function (Blueprint $table) {
    $table‐>string('email')‐>nullable();
    });
    
    在修改字段之前,请确保将 doctrine/dbal 依赖添加到 composer.json 文件中。Doctrine DBAL 库用于确定字段的当前状态, 并创建对该字段进行指定调整所需的 SQL 查询:
    composer require doctrine/dbal
    
    Schema::table('users', function (Blueprint $table) {
    $table‐>string('name', 50)‐>change();
    });
    
    Schema::table('users', function (Blueprint $table) {
    $table‐>renameColumn('from', 'to');
    });
    
    Schema::table('users', function (Blueprint $table) {
    $table‐>dropColumn('votes');
    });
    //删除多个字段
    Schema::table('users', function (Blueprint $table) {
    $table‐>dropColumn(['votes', 'avatar', 'location']);
    });
    
    $table‐>primary('id');//添加主键
    $table‐>primary(['id', 'parent_id']);//添加复合键
    $table‐>unique('email'); //添加唯一索引
    $table‐>index('state'); //添加普通索引
    $table‐>spatialIndex('location'); //添加空间索引(不支持 SQLite)
    
    $table‐>renameIndex('from', 'to')
    
    $table‐>dropPrimary('users_id_primary'); //从 users 表中删除主键
    $table‐>dropUnique('users_email_unique'); //从 users 表中删除唯一索引
    $table‐>dropIndex('geo_state_index'); //从 geo 表中删除基本索引
    $table‐>dropSpatialIndex('geo_location_spatialindex'); //从 geo 表中删除空间索引(不支持 SQLite)