TP5 模型更新主要使用静态方法 update 和动态方法 save
静态方法 update
直接使用模型类静态调用,例如 User 模型类更新主键为1的用户的 username 为 a
方式一
$data = ['id' => 1, 'username' => 'a'];User::update($data);
把更新条件 id 写在更新的数据数组里,因为 id 为模型默认的主键名称,所以方法能自动识别
如果需要更改模型的默认主键名称,更改模型的 pk 属性值( protected $pk = )即可
这种方式只支持主键作为更新条件
方式二
$data = ['username'=>'a'];User::update($data, ['id' => '1']);
把更新条件( id = 1 )写在 update 方法的第二个参数(数组)里,如下
$data = ['username'=>'a'];User::update($data, ['id' => '1']);
这种方式支持非主键字段作为更新条件,并且支持多个更新条件
例如把 username 等于 a 并且 status 等于 1 的 username 修改为 aa,如下
$data = ['username'=>'aa'];User::update($data, ['username' => 'a','status'=> 1]);
温馨提示
把方式一和方式二混写是不行的,如下
$data = ['id' => 1, 'username' => 'a'];User::update($data, ['status' => 1]);
本意是想把主键 id 等于1 而且 status 等于 1 的这行的 username 字段的字段值改为 a,如果把主键 id 写在 update 方法的第一个参数,status 写在 update 方法第二个参数(如上),生成的 SQL 如下
UPDATE `user` SET `username` = 'a' WHERE `id` = 1
只用上主键 id,没有用到 status,显然是错误的。
返回值
和 Db 类的 update 方法的返回值不同,Db 类的 update 方法返回的是影响行数,而模型的 update 方法返回的是更新数据的模型类的实例。
举例
把 id 等于 1 的 username 修改为 aa
$data = ['id' => 1, 'username' => 'aa'];$result = User::update($data);echo ("");var_dump($result);echo ("
");
返回的是更新数据的 User 类实例(当前更新数据有 id =1和 username = aa) ,更新数据保存在 User 类实例的 data 属性(数组)里,如下
object(app\index\model\User)#43 (2) { ["data"]=> array(3) { ["id"]=> int(1) ["username"]=> string(1) "aa" } ["relation"]=> array(0) { }}
生成的 SQL 语句如下
UPDATE `user` SET `username` = 'aa' WHERE `id` = 1
重要提醒
模型的 update 方法只管执行 SQL 不管 SQL 执行后的结果,执行 SQL 成功则返回当前更新数据的模型类实例,执行 SQL 失败则抛出异常,所以无需判断 update 方法的返回值。
模型的 update 方法无论更新条件的字段值是否存在都可以执行更新并返回更新数据的模型类实例而且不会有任何错误提示,所以更新前要先确保更新条件的字段值存在。
举例
把 id 等于 111 的 username 修改为 aa(id 等于 111 的用户在数据库内是不存在的),代码如下
$data = ['id' => 111, 'username' => 'aa'];$result = User::update($data);echo ("");var_dump($result);echo ("
");
返回
object(app\index\model\User)#43 (2) { ["data"]=> array(3) { ["id"]=> int(111) ["username"]=> string(2) "aa" } ["relation"]=> array(0) { }}
id 等于 111 的用户在数据库内是不存在的,但方法依旧能执行,并返回更新数据的模型类的实例,执行的 SQL 如下
UPDATE `user` SET `username` = 'aa' WHERE `id` = 111
执行 update 方法成功不代表更新数据成功,如果当前更新数据的字段名在数据库内是不存在的, update 方法是不会向数据库发送 SQL 语句的,测试如下
$data = ['name' => 'a']; // name 字段在表结构中是不存在的$result = User::update($data, ['id' => 1]);
因为模型在执行更新操作前,会发送一条 SQL 语句获得表结构,如下
SHOW COLUMNS FROM `user`
因为 name 字段在表结构中是不存在的,所以 update 方法是不会向数据库发送 SQL 语句的,而且 update 方法不会有任何错误提示,依然能返回更新数据的模型类实例,如下
object(app\index\model\User)#43 (2) { ["data"]=> array(1) { ["name"]=> string(1) "a" } ["relation"]=> array(0) { }}
动态方法 save
实例化模型类后动态调用,例如 User 对象更新主键为1的用户的 username 为 a
$user = new User();$data = ['username' => 'a'];$where = ['id' => 1];$result = $user->save($data, $where);
save 方法的使用方式分两种情况
1、先查询出数据后再进行更新
$user = User::get(1);//取得主键为1的 User 类实例$data = ['username' => 'aa'];$result = $user->save($data);
因为这种方式首先得取得查询条件对应数据的模型类实例(取得的数据会保存在模型类实例的 data 属性(数组)里),然后模型类实例调用 save 方法的时候就会自动地使用自身 data 属性里的主键作为更新条件,所以不需要在 save 方法的参数里填写任何更新条件。
特别提示
这种更新方式是使用主键作为更新条件的,就算在 save 方法的第二个参数里填入其他的更新条件也是没用的,如下
$user = User::get(1);$data = ['username' => 'a'];$user->save($data, ['status' => 1]);
在 save 方法的第二个参数填入另外一个更新条件 status = 1
生成的 SQL 如下
UPDATE `user` SET `username` = 'a' WHERE `id` = 1
很显然,只会使用到主键 id ,而 status = 1 是失效的
2、不经过查询数据,直接使用模型类的实例进行更新
$user = new User();$data = ['username' => 'a'];$where = ['id' => 1];$result = $user->save($data, $where);
因为这种方式没有像第一种方式先取得某条记录的模型类实例(没有先取得某条记录的主键),所以这种方式调用 save 方法的时候就需要填写更新条件,更新条件并不一定是主键,可以是其他字段,所以当前方法可以一次性更新多条数据,如下
$user = new User();$data = ['status' => 1];$where = ['status' => 0];$user->save($data, $where);
把当前 User 模型对应的数据表中的 status 字段值等于1的行的 status 字段值更改为 0
生成的 SQL 如下
UPDATE `user` SET `status` = 1 WHERE `status` = 0
版本差异
根据 ThinkPHP 的版本的不同,save 方法的主键的写法也有所不同,tp5.1 的 save 方法的主键必须写在第二个参数中(如上 $where),如果主键写在第一个参数中(如下 $data)save 方法将无法自动识别出主键,如下
$user = new User();$data = ['username' => 'aa', 'id' => 1];$user->save($data);
因为 save 方法无法自动识别出主键,所以当前 save 方法执行的是新增操作
如果想要 save 方法自动识别出主键,需要在save 方法前面调用 isUpdate 方法,指明该方法执行的是更新操作,如下
$data = ['username' => 'a','id' => 1];$result = $user->isUpdate()->save($data);
执行成功
tp5 版本可以在第一个参数里自动识别出主键,如下
$data = ['username' => 'a','id' => 1];$result = $user->save($data);
执行成功
返回值
V5.1.6+版本以前
save 方法返回影响的记录数
V5.1.6+版本以后
统一返回布尔值,如果执行 save 方法成功则返回 true(哪怕更新的行数是 0 也是返回 true ),并只有当 before_update 事件返回 false 的时候返回 false
重要提醒
从 V5.1.6+版本开始,save 方法只管执行 SQL 不管 SQL 执行后的结果,执行 SQL 成功则返回 true(哪怕更新的行数是 0 也是返回 true )
save 方法无论更新条件的字段值是否存在都可以执行更新并返回 true 而且不会有任何错误提示,所以更新前要先确保更新条件的字段值存在。
3、和静态方法 update 一样,执行 save 方法成功不代表更新数据成功,如果当前更新数据的字段名在数据库内是不存在的, save 方法是不会向数据库发送 SQL 语句的,测试如下
$user = new User();$data = ['name' => 'a'];// name 字段在表结构中是不存在的$where = ['id' => 1];$user->save($data,$where);
因为模型在执行更新操作前,会发送一条 SQL 语句获得表结构,如下
SHOW COLUMNS FROM `user`
因为 name 字段在表结构中是不存在的,所以 save 方法是不会向数据库发送 SQL 语句的,而且 save 方法不会有任何错误提示,依然能返回 true,如下
bool(true)
更重要提醒
save 方法会修改调用它的对象的数据
$obj = new User();$user = $obj->find(1);echo ("");var_dump($user);echo ("
");//更新前的 User 类实例object(app\index\model\User)#49 (2) { ["data"]=> array(9) { ["id"]=> int(1) ["username"]=> string(1) "a" ["password"]=> string(32) "47bce5c74f589f4867dbd57e9ca9f808" ["email"]=> NULL ["mobile"]=> NULL ["level"]=> int(1) ["status"]=> int(0) ["create_time"]=> int(1667095117) ["update_time"]=> int(1667368159) } ["relation"]=> array(0) { }}//执行更新$data = ['username' => 'aa', 'status' => 1];$user->save($data);echo ("");var_dump($user);echo ("
");//执行更新后的 User 类实例object(app\index\model\User)#49 (2) { ["data"]=> array(9) { ["id"]=> int(1) ["username"]=> string(2) "aa" ["password"]=> string(32) "47bce5c74f589f4867dbd57e9ca9f808" ["email"]=> NULL ["mobile"]=> NULL ["level"]=> int(1) ["status"]=> int(1) ["create_time"]=> int(1667095117) ["update_time"]=> int(1667368159) } ["relation"]=> array(0) { }}
如上,User 类实例的 username 已经从 a 变成了 aa,status 已经从 0 变成1,和 save 方法更新数据库里的数据是保持一致的。
更更重要提醒
因为模型的新增方法和更新方法都是 save 方法,所以 tp5 框架有一套默认的规则来识别当前 save 方法要执行新增操作还是更新操作
不查询数据,直接模型对象调用 save 方法,表示新增
查询数据后调用 save 方法表示更新
save 方法传入更新条件表示更新
可以在执行 save 方法前执行 isUpdate ( true ) 方法指定当前 save 方法执行更新操作
不要用同一个模型类实例执行多次 save 方法,会导致部分重复数据不再更新,正确的方式应该是先查询后更新或者使用模型类的 update 方法更新
来源地址:https://blog.csdn.net/weixin_44161401/article/details/127615917