原生查询

use Illuminate\Support\Facades\DB;

// 运行原生SQL,注意,不要使用字符串拼接,采用参数绑定的形式
// 原生SQL必须是完整的表名,带前缀的
$info = DB::select('select * from sxy_users where id = ?',[1]);

备注:时间字段无法自动写入,需手动创建

DB查询构造器

新增

use Illuminate\Support\Facades\DB;

// $data可以是一维数组和二维数据,二维数组表示批量插入
$data = [
	'name'=>'shuxiaoyuan',
	'age'=>18,
];
$info = DB::table('users')->insert($data);

//得到表的自增ID,如果有的话
$id = DB::table('users')->insertGetId($data);

删除

use Illuminate\Support\Facades\DB;

DB::table('users')->delete();
DB::table('users')->where('id', '>', 66)->delete();

//清空整张表,并且重置自增ID
DB::table('users')->truncate();

修改

use Illuminate\Support\Facades\DB;

$data = [
	'name'=>'shuxiaoyuan',
	'age'=>19,
];
$info = DB::table('users')->where('id',2)->update($data);

//自增和自减,第二个参数可选
DB::table('users')->increment('age');
DB::table('users')->increment('age', 5);
DB::table('users')->decrement('age');
DB::table('users')->decrement('age', 5);

查询

use Illuminate\Support\Facades\DB;

//获取单条数据
$info = DB::table('users')->where('email','xx@163.com')->first();

//获取主键ID获取数据
$info = DB::table('users')->find(1);

//获取多条数据
$info = DB::table('users')->where('name','shuxiaoyuan')->get();

// 各种where查询和聚合等,看 ORM 吧

Eloquent ORM操作数据库

可以设置的属性

<?php

/**
 * 请提供简单说明
 *
 * User: 舒孝元
 * Date: 2020/7/7 11:35
 * Mail: sxy@shuxiaoyuan.com
 * Website: https://www.shuxiaoyuan.com
 */


namespace App\Models;


use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class User extends Model {

    /**
     * 匿名全局作用域
     */
    protected static function boot() {
        parent::boot();

        static::addGlobalScope('creation_date', function (Builder $builder) {
            $builder->where('creation_date', '>', 1604555245);
        });
    }

    // 软删,需要表中有对应字段:deleted_at
    use SoftDeletes;

    // 手动指定数据库连接,不指定即为默认
    protected $connection = 'local_db';

    // 手动指定表名,默认为大驼峰复数形式(UserInfo->user_infos)
    protected $table = 't_users';

    // 手动定义主键,默认为 id
    protected $primaryKey = 'idd';

    // 指示模型主键是否递增,默认为 int 自增型
    public $incrementing = false;

    // 自动递增ID的“类型”(主键不是一个整数,你需要将模型上受保护的 $keyType 属性设置为 string)
    protected $keyType = 'string';

    // 表明模型是否应该被打上时间戳,默认true,需要配合数据数据字段,默认是 created_at 和 updated_at
    public $timestamps = true;

    // 模型日期列的存储格式,默认为 Y-m-d H:i:s
    // 采用PHP标准定义:https://www.php.net/manual/zh/function.date.php
    protected $dateFormat = 'U'; //从 Unix 纪元(January 1 1970 00:00:00 GMT)开始至今的秒数

    // 自定义时间戳字段名,默认为 created_at  updated_at
    const CREATED_AT = 'creation_date';
    const UPDATED_AT = 'last_update';

    /**
     * 模型批量插入,需要开启以下两个中的一个,互斥
     * $fillable // 可以被批量赋值的属性
     * $guarded // 不能被批量赋值的属性
     *
     * @var array
     */
    // 可以被批量赋值的属性
    protected $fillable = [];

    // 不能被批量赋值的属性
    protected $guarded = [];// 空表示所有的都可赋值

    // 查询时默认隐藏不显示的字段,黑名单
    protected $hidden = ['password'];

    // 查询时只显示指定的字段,白名单
    protected $visible = [
        'idd', 'name'
    ];

    // 追加数据库中没有的字段,需要结合下面的修改器一起
    protected $appends = ['you_sb'];

    public function getYouSbAttribute() {
        // 这个值你可以随便从其他地方获取
        $this->attributes['you_sb'] = 'yes';
        return $this->attributes['you_sb'];
    }

    // 为模型的某些属性定义默认值
    protected $attributes = [
        'remember_token' => '12345612456789',
    ];

    /**
     * 属性类型转换,可用的有如下所示
     *
     * integer、real、float、double、decimal:<digits>、string、
     * boolean、object、array、collection、date、datetime、timestamp
     * @var array
     */
    protected $casts = [
        'name'          => 'decimal:2',
        'creation_date' => 'date:Y-m-d',
        'last_update'   => 'datetime:Y-m-d H:i:s'
    ];

    /**
     * 定义一个访问器,定义语法: get字段名Attribute 字段名需要使用 驼峰式 命名
     *
     * 用法见 App\Http\Controllers\Test\IndexController::type12
     *
     * @param $value
     * @return string
     */
    public function getFirstNameAttribute($value) {
        return ucfirst($value);
    }

    /**
     * 定义一个修改器,定义语法:set字段名Attribute 字段名需要使用 驼峰式 命名
     *
     * 将 first_name 字段全部替换成小写,然后拼接一个字符串
     *
     * 用法见 App\Http\Controllers\Test\IndexController::type12
     *
     * @param $value
     */
    public function setFirstNameAttribute($value) {
        $this->attributes['first_name'] = strtolower($value) . '这是修改器加上的';
    }

    /**
     * 查找或创建,firstOrCreate | firstOrNew
     * 更新或创建,updateOrCreate
     *
     * @param $data
     * @return mixed
     */
    public static function addOne($data) {
        $data = ['idd' => 's1604560200'];
        return User::firstOrCreate($data);
    }
}

// 使用 create 方法,需要在模型设置可批量更新
$data = [
    'name'=>'shuxiaoyuan',
    'age'=>18,
];
$info = User::create($data);
$id = $info->id;

// 使用 save 方法
$user = new User;
$user->name = 'yuanyuan';
$user->age = 18;
$user->save();
$id = $user->id;

// 存在则更新,不存在就创建
GamesData::updateOrCreate(['openId' => $data['openId']], $data);

// 根据主键删除
User::where()->delete();
User::destroy(1); // 软删
User::destroy([2,3]);

// 先查后删
$info = User::find(2);
$info->delete();

User::where('id',1)->delete();

// 软删,在模型中引入 SoftDeletes
use SoftDeletes;

// 查询被软删的模型
$temp = Article::onlyTrashed()->with('category')->paginate(15);

// 包含软删除模型
return Article::withTrashed()->where('id', $id)->with('category')->get();

// 恢复软删
return Article::where('id', $id)->restore();

// 物理删除,永久删除
return Article::where('id', $id)->forceDelete();

$data = [
    'name'=>'shuxiaoyuan',
    'age'=>18,
];

$info = User::where('id',7)->update($data);

// 使用 save 方法
$info = User::find(7);
$info->name = 'sss';
$info->age = 19;
$info->save();

自增自减

// 自增,第二个参数不填默认步长为 1
VerifyMaterialGroup::where('id', $id)->increment('number', $count);
VerifyMaterialGroup::where('id', $id)->decrement('number', $count);

// 通过主键查询
$info = User::find(1);
$info = User::find([1,2,4,6]);//数组形式,建议控制数量

// 查询一条数据
$info = User::where('name','shuxiaoyuan')->first();

// 只需要单个值
$info = User::where('name','shuxiaoyuan')->value('age');

// 获取包含单个列值的数组
// groupBy可以去重
$info = Staff::where('company_id', $id)->groupBy('department')->pluck('department');

// 查询所有数据时指定查询的字段
$info = User::all('id','name');
$info = User::all(['id','name']);
注:all方法是模型本身封装的一个静态方法,只能直接调用,前面不能调用where等方法。

// count max min avg sum 查询,没啥好说的,直接用就行

// 大数据处理,chunk 或 cursor 游标,具体使用看文档
DB::table('users')->orderBy('id')->chunk(100, function($users) {
	// 处理结果集...
	//可以return false来终止运行
	return false;
});

// 分页查询
SubscribeUser::where('id', '>', 100)->paginate(100);

// 带条件
where('id','0');
where('id','>','100');
where('id','<>','121');
->orWhere('name', 'John')

// 模糊查询
->where('name', 'like', '%' . $name . '%')

//whereBetween 方法验证列值是否在给定值之间
->whereBetween('votes', [1, 100])->get();

//whereNotBetween 方法验证列值不在给定值之间
->whereNotBetween('votes', [1, 100])

//whereIn  whereNotIn 方法验证给定列的值是否在给定数组中
->whereIn('id', [1, 2, 3])
->whereNotIn('id', [1, 2, 3])

//whereNull 方法验证给定列的值为 NULL
//whereNotNull 方法验证给定列的值不是 NULL

// whereDate 方法用于比较字段值和日期
->whereDate('created_at', '2018-11-11')

// whereMonth 方法用于比较字段值和一年中的指定月份
->whereMonth('created_at', '11')

// whereDay 方法用于比较字段值和一月中的指定日期
->whereDay('created_at', '11')

// whereYear 方法用于比较字段值和指定年
->whereYear('created_at', '2018')

// whereTime 方法用于比较字段值和指定时间
->whereTime('created_at', '=', '11:11')

//whereColumn 方法用于验证两个字段是否相等
->whereColumn('updated_at', 'created_at')
->whereColumn('updated_at', '>', 'created_at')

// 多条件数组通过 and 操作符进行链接
->whereColumn([
	['first_name', '=', 'last_name'],
	['updated_at', '>', 'created_at']
]

//inRandomOrder 方法可用于对查询结果集进行随机排序
->inRandomOrder()

//悲观锁
//可以避免被选择的行被修改直到事务提交
->sharedLock()

//避免选择行被其它共享锁修改或删除
->lockForUpdate()

// 查数据库最大主键
User::max('id')

分页查询修改数据

$data = Image::query()->where('user_id', 10)->paginate(10);

// 获取 item 并修改
$data->getCollection()->transform(function ($model) {
    // 修改 expires_time 字段的显示
    $model->expires_time = date('Y-m-d H:i:s');

    // 添加字段
    $model->name = 'shuxiaoyuan';

    // 删除字段
    unset($model->image_url);

    return $model;
});

// 组建自己的 item
for ($i = 1; $i <= 10; $i++) {
    $collect[] = [
        'id'   => $i,
        'name' => Str::random(),
        'time' => time(),
        'url'  => 'https://www.shuxiaoyuan.com'
    ];
}

// 直接替换整个 item
$data->setCollection(collect($collect));

return Tools::outSuccessInfo($data);

多条件查询(and,or嵌套查询)

# 原生 SQL
select
    *
from
    homework
where
    (id between 1 and 10 or id between 50 and 70)
    and complete = 1
    and (title like 'a%' or title like 'b%');

# ORM 查询
$homeworks = Homework::where(function ($query) {
    $query->whereBetween('id', [1, 10])
          ->orWhereBetween('id', [50, 70]);
})->where('complete', 1)
->where(function ($query) {
    $query->where('title', 'like', 'a%')
          ->orWhere('title', 'like', 'b%');
})->get();

leftjoin 多条件匹配

# 方式就是使用闭包
leftjoin('db', function ($join) {···});

## && 使用 on
$data = DB::table('ikea_articles as a')
    ->leftJoin('ikea_likes as b', function ($join) {
        $join->on('b.a_id', '=', 'a.id')
             ->on('b.openid', '=', 'a.openid');
    })


## || 使用 orOn
$data = DB::table('ikea_articles as a')
    ->leftJoin('ikea_likes as b', function ($join) {
        $join->on('b.a_id', '=', 'a.id')
             ->orOn('b.openid', '=', 'a.openid');
    })

## 多条件查询
$data = DB::table('ikea_articles as a')
    ->leftJoin('ikea_likes as b', function ($join) use($openid) {
        $join->on('b.a_id', '=', 'a.id')
             ->where('b.openid', '=', $openid);
    })

with 实现动态添加 where 条件

$query->with([
    'student' => function ($q) use ($student_id) {
        $q->where('id', $student_id);
    },
    'class',
])
->select('id','name')
->where('id',$id)
->get();

when用法

//条件分支,如果 event_id 为真,则执行,否则执行
return BuyEventSuccessfuls::where('store_id', $store_id)
   ->when($event_id, function ($query) use ($event_id) {
      return $query->where('event_id', $event_id);
   }, function ($query) use ($eventIds) {
      return $query->whereIn('event_id', $eventIds);
   })->select('id', 'name', 'mobile', 'status')
   ->where('status', '=', "$status")
   ->paginate(20)
   ->toArray();

事务处理

注:transaction 方法接收一个可选参数作为第二个参数,用于定义死锁发生时事务的最大重试次数,如果尝试次数超出指定值,会抛出异常

手动开启和提交事务

// 手动开启事务
DB::beginTransaction();

// 提交事务
DB::commit();

// 回滚事务
DB::rollBack();

// 示例:
DB::beginTransaction();
try {
    // 数据库处理,更新插入等
    DB::commit(); // 提交事务
    return Tools::outSuccess();
} catch (\Exception $exception) {
    Log::error(__METHOD__ . __FUNCTION__, ['info' => $exception]);
    DB::rollBack();
    return Tools::outError(0, '保存失败,请稍后重试');
}


// 回滚事务
DB::rollBack();

例一:

//事务闭包函数传参,通过 use() 进行传参
$a = DB::transaction(function () use ($store, $login, $store_id) {
	try {
		DB::table('store')->where('serial_number', $store_id)->update($store);
		DB::table('consume_login')->where('store_id', $store_id)->delete();
		DB::table('consume_login')->insert($login);
		DB::commit();//手动提交事务
		return true;
	} catch (\Exception $exception) {
		DB::rollBack();//手动事务回滚
		//$exception->getMessage(); //错误信息
		return false;
	}
});

//根据$a来判断是成功提交事务了还是回滚事务了

例二:

$a = DB::transaction(function () use ($request,$id) {
   $data = $request->only('name', 'serial_number', 'addre', 'lng', 'lat', 'channel', 'type', 'area', 'city');
   $consume_account = $request->json('accounts');
   foreach ($consume_account as $k => $v) {
      $consume_account[$k]['store_id'] = $data['serial_number'];
      $consume_account[$k]['password'] = password_hash($consume_account[$k]['password'], PASSWORD_BCRYPT);
      $consume_account[$k]['cookie_info'] = $v['username'] . ':' . $data['serial_number'] . ':' . time();
      $consume_account[$k]['state'] = 0;
      $consume_account[$k]['created_at'] = date('Y-m-d H:i:s');
      $consume_account[$k]['updated_at'] = date('Y-m-d H:i:s');
   }
   try {
      Store::where('id', $id)->update($data);
      DB::table('consume_login')->insert($consume_account);
      DB::commit();
      return true;
   } catch (\Exception $exception) {
      DB::rollBack();
      return false;
   }
});

修改器

模型关联

远程一对一(多)

参数一: 最终模型 参数二: 中间模型 参数三: 中间模型的字段,中间和本地的关联 参数四: 最终模型的字段,一般是最终模型主键,最终和中间的关联 参数五: 本地模型的字段,一般是本地模型主键,本地和中间的关联 参数六: 中间模型的字段,中间和最终的关联