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
// 新增一个用户 save
public 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();
// 获取自增ID
echo $user->id;
这里其实是获取模型的主键,如果你的主键不是id
,而是user_id
的话,其实获取自增ID就变成这样:
<?php
$user = new User;
$user->name = 'thinkphp';
$user->email = 'thinkphp@qq.com';
$user->save();
// 获取自增ID
echo $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.16
public function delOneUserById($id)
{
$offectRows = UserModel::get($id)->delete();
return $offectRows ? '删除成功' : '删除失败';
}
使用 destoy方法删除,也是可以通过主键删除。返回值也是布尔值。当destroy方法传入空值(包括空字符串和空数组)的时候不会做任何的数据删除操作,但传入0则是有效的
<?php
// 删除多个用户通过 ID
public function delMulUserByID($arr)
{
return (UserModel::destroy($arr)) ? '删除成功' : '删除失败';
}
2.2 条件删除
可以使用闭包
<?php
// 条件删除闭包
public function delByConditions1()
{
$res = UserModel::destroy(function($query){
$query->where('gender', '=', 2);
});
return $res ? '删除成功' : '删除失败';
}
或者通过数据库类的查询条件删除
<?php
User::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() 方法去作为批量更新,影响性能。
模型支持调用数据库的方法直接更新数据,例如:
<?php
User::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
),支持在模型中单独设置查询数据集的返回对象的名称,例如:
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
// 设置返回数据集的对象名
protected $resultSetType = '\app\common\Collection';
}
resultSetType
属性用于设置自定义的数据集使用的类名,该类应当继承系统的think\model\Collection
类。
4.4 使用查询构造器
在模型中仍然可以调用数据库的链式操作和查询方法,可以充分利用数据库的查询构造器的优势。
例如:
<?php
User::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 聚合查询
同样在模型中也可以调用数据库的聚合方法查询,例如:
<?php
User::count();
User::where('status','>',0)->count();
User::where('status',1)->avg('score');
User::max('score');
4.8 数据分批处理
模型也可以支持对返回的数据分批处理,这在处理大量数据的时候非常有用,例如:
<?php
User::chunk(100,function($users) {
foreach($users as $user){
// 处理user模型对象
}
});
4.9 使用游标查询
模型也可以使用数据库的cursor
方法进行游标查询,返回生成器对象
<?php
foreach(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类查询无效。
模型查询的最佳实践原则是:在模型外部使用静态方法进行查询,内部使用动态方法查询,包括使用数据库的查询构造器。模型的查询始终返回对象实例,但可以和数组一样使用。