1. 增
- 模型添加一条数据可以使用 save(),也可以使用 create() ,只不过后者是静态方式
- create() 不可以插入多条数据
- 不推荐,使用 saveAll() 添加多条数据,性能很差,还不如使用 Db::insert()
1.1 save() 添加一条数据
- 5.1.6 + 版本开始返回数据是否添加成功的布尔值
可以这么使用(几乎也不会有人这么去使用):
<?php$user = new User;$user->name = 'thinkphp';$user->email = 'thinkphp@qq.com';$user->save();
常见的使用方式:
<?php// 新增一个用户 savepublic function addOneUser($user){$model = new userModel();return ($model->save($user)) ? '增加成功' : '增加失败';}
如果需要过滤字段:
<?php$user = new User;// 过滤post数组中的非数据表字段数据$user->allowField(true)->save($_POST);
如果你通过外部提交赋值给模型,并且希望指定某些字段写入,可以使用:
<?php$user = new User;// post数组中只有name和email字段会写入$user->allowField(['name','email'])->save($_POST);
最佳的建议是模型数据赋值之前就进行数据过滤,例如:
<?php$user = new User;// 过滤post数组中的非数据表字段数据$data = Request::only(['name','email']);$user->save($data);
1.2 replace 写入
5.1.14+版本开始,save方法可以支持replace写入。
<?php$user = new User;$user->name = 'thinkphp';$user->email = 'thinkphp@qq.com';$user->replace()->save();
1.3 获取自增ID
如果要获取新增数据的自增ID,可以使用下面的方式:
<?php$user = new User;$user->name = 'thinkphp';$user->email = 'thinkphp@qq.com';$user->save();// 获取自增IDecho $user->id;
这里其实是获取模型的主键,如果你的主键不是id,而是user_id的话,其实获取自增ID就变成这样:
<?php$user = new User;$user->name = 'thinkphp';$user->email = 'thinkphp@qq.com';$user->save();// 获取自增IDecho $user->user_id;
1.4 saveAll() 添加多条数据 不推荐使用!
使用saveAll(),但是真的不推荐使用这个… …
- saveAll 方法实际上是 循环数据数组,每一条数据进行一遍save方法,批量插入数据时慎用!!!每一条数据都会走一次数据库请求进行insert操作,数据量大的时候非常占用时间。批量插入数据建议使用Db::insertAll() 方法,只会进行一次数据库请求
saveAll方法新增数据返回的是包含新增模型(带自增ID)的数据集对象。
<?php$user = new User;$list = [['name'=>'thinkphp','email'=>'thinkphp@qq.com'],['name'=>'onethink','email'=>'onethink@qq.com']];$user->saveAll($list);
saveAll方法新增数据默认会自动识别数据是需要新增还是更新操作,当数据中存在主键的时候会认为是更新操作,如果你需要带主键数据批量新增,可以使用下面的方式:
<?php$user = new User;$list = [['id'=>1, 'name'=>'thinkphp', 'email'=>'thinkphp@qq.com'],['id'=>2, 'name'=>'onethink', 'email'=>'onethink@qq.com'],];$user->saveAll($list, false);
1.5 静态方法 create()
- 和
save方法不同的是,create方法返回的是当前模型的对象实例。- create 不支持插入多条数据
还可以直接静态调用create方法创建并写入:
<?php$user = User::create(['name' => 'thinkphp','email' => 'thinkphp@qq.com']);echo $user->name;echo $user->email;echo $user->id; // 获取自增ID
create方法的第二个参数可以传入允许写入的字段列表(传入true则表示仅允许写入数据表定义的字段数据),例如:
<?php// 只允许写入name和email字段的数据$user = User::create(['name' => 'thinkphp','email' => 'thinkphp@qq.com'], ['name', 'email']);echo $user->name;echo $user->email;echo $user->id; // 获取自增ID
V5.1.14+版本开始,支持replace操作,使用下面的方法:
<?php$user = User::create(['name' => 'thinkphp','email' => 'thinkphp@qq.com'], ['name','email'], true);
2. 删
- 推荐使用 destory() 删除数据
2.1 通过ID删除数据
通过模型方法的 get 先查到数据然后,使用 delete 方法删除。V5.16 版本后返回值改为了 布尔值,而不是影响行数。
<?php$user = User::get(1);$user->delete();// 删除一个用户通过 ID 5.16public function delOneUserById($id){$offectRows = UserModel::get($id)->delete();return $offectRows ? '删除成功' : '删除失败';}
使用 destoy方法删除,也是可以通过主键删除。返回值也是布尔值。当destroy方法传入空值(包括空字符串和空数组)的时候不会做任何的数据删除操作,但传入0则是有效的
<?php// 删除多个用户通过 IDpublic function delMulUserByID($arr){return (UserModel::destroy($arr)) ? '删除成功' : '删除失败';}
2.2 条件删除
可以使用闭包
<?php// 条件删除闭包public function delByConditions1(){$res = UserModel::destroy(function($query){$query->where('gender', '=', 2);});return $res ? '删除成功' : '删除失败';}
或者通过数据库类的查询条件删除
<?phpUser::where('id','>',10)->delete();
直接调用数据库的
delete方法的话无法调用模型事件。
3. 改
3.1 查找并更新
还是使用 save() 方法,修改
<?php// 修改一个用户public function updOneUserById($id){$user = UserModel::get($id);$user->name = 'thinkphp';$user->email = 'thinkphp@qq.com';$user->age = 17;return ($user->save()) ? '修改成功' : '修改失败';}
对于复杂的查询条件,也可以使用查询构造器来查询数据并更新
<?php$user = User::where('status',1)->where('name','liuchen')->find();$user->name = 'thinkphp';$user->email = 'thinkphp@qq.com';$user->save();
save 方法更新数据,只会更新变化的数据,对于没有变化的数据是不会进行重新更新的。如果你需要强制更新数据,可以使用下面的方法:
<?php$user = User::get(1);$user->name = 'thinkphp';$user->email = 'thinkphp@qq.com';$user->force()->save();
如果要执行SQL函数更新,那么在 **V5.1.8+** 版本可以使用下面的方法
<?php$user = User::get(1);$user->name = 'thinkphp';$user->email = 'thinkphp@qq.com';$user->score = Db::raw('score+1');$user->save();
如果只是字段的增加/减少,也可以直接用inc/dec方式
<?php$user = User::get(1);$user->name = 'thinkphp';$user->email = 'thinkphp@qq.com';$user->score = ['inc', 1];$user->save();
3.2 直接更新数据 save()
可以 save() 方法中直接添加第二个参数来设置
<?php// 修改一条记录 直接修改数据public function updOneUserById2($id){// save方法第二个参数为更新条件$res = (new UserModel())->save(['name' => 'thinkphp','email' => 'thinkphp@qq.com'],['id' => $id]);return $res ? '修改成功' : '修改失败';}
上面两种方式更新数据,如果需要过滤非数据表字段的数据,可以使用:
<?php$user = new User;// 过滤post数组中的非数据表字段数据$user->allowField(true)->save($_POST,['id' => 1]);
如果你通过外部提交赋值给模型,并且希望指定某些字段写入,可以使用:
<?php$user = new User();// post数组中只有name和email字段会写入$user->allowField(['name','email'])->save($_POST, ['id' => 1]);
最佳建议是在传入模型数据之前就进行过滤,例如:
<?php$user = new User();// post数组中只有name和email字段会写入$data = Request::only(['name','email']);$user->save($data, ['id' => 1]);
3.3 批量更新数据
不使用 saveAll() 方法去作为批量更新,影响性能。
模型支持调用数据库的方法直接更新数据,例如:
<?phpUser::where('id', 1)->update(['name' => 'thinkphp']);
数据库的
update方法返回影响的记录数
或者使用模型的静态update方法更新:
User::update(['id' => 1, 'name' => 'thinkphp']);
模型的
update方法返回模型的对象实例 上面两种写法的区别是第一种是使用的数据库的update方法,而第二种是使用的模型的update方法(可以支持模型的修改器、事件和自动完成)。
3.4 自动识别 isUpdate()
我们已经看到,模型的新增和更新方法都是save方法,系统有一套默认的规则来识别当前的数据需要更新还是新增。
- 实例化模型后调用
save方法表示新增; - 查询数据后调用
save方法表示更新; save方法传入更新条件后表示更新;
如果你的数据操作比较复杂,可以用isUpdate方法显式的指定当前调用save方法是新增操作还是更新操作。
显式更新数据:
<?php// 实例化模型$user = new User;// 显式指定更新数据操作$user->isUpdate(true)->save(['id' => 1, 'name' => 'thinkphp']);
显式新增数据:
<?php$user = User::get(1);$user->name = 'thinkphp';// 显式指定当前操作为新增操作$user->isUpdate(false)->save();
4. 查
4.1 获取单个数据 get()
使用 get() 方法,通过ID查询数据
<?php// 查询一个用户 get() 方法public function selOneUseById2($id){return json(userModel::get($id));}
使用查询构造器
<?php// 查询一个用户 查询构造器public function selOneUseById($id){return json(userModel::where('id', '=', $id)->findOrEmpty());}
4.2 获取多条数据
使用模型的 all() 方法,通过ID查询多条数据
<?php// 查询多条数据 all 方法public function selMulUserById($arr){return json(userModel::all($arr));}
要更多的查询支持,一样可以使用查询构造器:
<?php// 使用查询构造器查询$list = User::where('status', 1)->limit(3)->order('id', 'asc')->select();foreach($list as $key=>$user){echo $user->name;}
查询构造器方式的查询可以支持更多的连贯操作,包括排序、数量限制等。
V5.1.21+版本开始,可以在all方法之前使用Db类的查询链式操作,
<?php// 使用查询构造器查询$list = User::where('status', 1)->limit(3)->order('id', 'asc')->all();foreach($list as $key=>$user){echo $user->name;}
4.3 自定义数据集对象
模型的all方法或者select方法返回的是一个包含多个模型实例的数据集对象(默认为\think\model\Collection),支持在模型中单独设置查询数据集的返回对象的名称,例如:
<?phpnamespace app\index\model;use think\Model;class User extends Model{// 设置返回数据集的对象名protected $resultSetType = '\app\common\Collection';}
resultSetType属性用于设置自定义的数据集使用的类名,该类应当继承系统的think\model\Collection类。
4.4 使用查询构造器
在模型中仍然可以调用数据库的链式操作和查询方法,可以充分利用数据库的查询构造器的优势。
例如:
<?phpUser::where('id',10)->find();User::where('status',1)->order('id desc')->select();User::where('status',1)->limit(10)->select();
使用查询构造器直接使用静态方法调用即可,无需先实例化模型。
4.5 获取某个字段或者某个列的值
<?php// 获取某个用户的积分User::where('id',10)->value('score');// 获取某个列的所有值User::where('status',1)->column('name');// 以id为索引User::where('status',1)->column('name','id');
value和column方法返回的不再是一个模型对象实例,而是纯粹的值或者某个列的数组。
4.6 动态查询
支持数据库的动态查询方法,例如:
<?php// 根据name字段查询用户$user = User::getByName('thinkphp');// 根据email字段查询用户$user = User::getByEmail('thinkphp@qq.com');
4.7 聚合查询
同样在模型中也可以调用数据库的聚合方法查询,例如:
<?phpUser::count();User::where('status','>',0)->count();User::where('status',1)->avg('score');User::max('score');
4.8 数据分批处理
模型也可以支持对返回的数据分批处理,这在处理大量数据的时候非常有用,例如:
<?phpUser::chunk(100,function($users) {foreach($users as $user){// 处理user模型对象}});
4.9 使用游标查询
模型也可以使用数据库的cursor方法进行游标查询,返回生成器对象
<?phpforeach(User::where('status', 1)->cursor() as $user){echo $user->name;}
user变量是一个模型对象实例。
4.10 查询缓存
get方法和all方法的支持使用查询缓存,可以直接在第二个参数传入true表示开启查询缓存。
<?php$user = User::get(1,true);$list = User::all('1,2,3',true);
如果要设置缓存标识,则必须在第三个参数传入缓存标识。
<?php$user = User::get(1,'','user');$list = User::all('1,2,3','','user_list');
4.11 主库读取
如果你采用分布式数据库,如果写入数据后立刻进行该数据的读取,将会导致数据读取失败,原因是数据库同步尚未完成。
规范的解决方案是在写入数据后,不要马上从从库读取,而应该调用master方法读取主库。
<?php$user = new User;$user->name = 'thinkphp';$user->email = 'thinkphp@qq.com';$user->save();// 从主库读取数据$user->master()->get($user->id);
或者对关键的逻辑启用事务,在事务中的数据库操作都是基于主库的。V5.1.12+版本开始,你可以在数据库配置文件中设置
<?php// 主库写入后从主从库读取'read_master' => true
设置开启后,一旦你的模型有写入操作,那么该请求后续的同一个模型的读操作都会自动从主库读取。
如果你只需要对某个模型生效,可以在你完成主库写入操作后,执行下模型类的readMaster方法。
<?php$user = new User;$user->name = 'thinkphp';$user->email = 'thinkphp@qq.com';$user->save();// 从主库读取数据$user->readMaster(true)->get($user->id);
注意上述设置和方法仅对模型查询有效,直接调用Db类查询无效。
模型查询的最佳实践原则是:在模型外部使用静态方法进行查询,内部使用动态方法查询,包括使用数据库的查询构造器。模型的查询始终返回对象实例,但可以和数组一样使用。
