Laravel模型序列更新函数单次执行失效,需执行两次的问题
我来帮你拆解这个问题的本质,以及给出一次性解决的办法:
这个问题其实是MySQL的UPDATE语句执行逻辑导致的:在同一条UPDATE语句中,所有字段的更新计算都是基于该行更新前的原始数据,而不是刚刚更新后的字段值。
你写的UPDATE table SET number = @a+1, table_number = number+1里,table_number引用的number是这条语句执行前的旧值(如果之前number是空,那number+1的结果还是空),而不是你刚设置的@a+1。这就是为什么第一次执行只有number被正确赋值,table_number还是空的原因。
至于执行两次能生效,是因为第一次执行后number已经有了有效值,第二次执行时table_number = number+1就会用上第一次更新后的number值,自然就能填充了,但这显然是绕了弯路。
有两种简洁的方式可以让你一次性完成更新,不用执行两次:
方式一:直接通过变量计算table_number的值
既然number的取值是@a+1,那table_number就是@a+2,我们可以直接在UPDATE语句里用这个表达式,完全不用依赖number字段的新值:
// 把变量初始化和UPDATE合并成一条语句 $numbering = DB::update(DB::raw(" SET @a := 0; UPDATE table SET number = @a := @a + 1, table_number = @a + 1; ")); return $numbering;
这里注意用@a := @a + 1来更新变量的值,确保@a能正确递推,table_number直接取递推后@a加1,刚好是number+1的结果。
方式二:将变量初始化嵌入UPDATE语句
我们还可以把@a的初始化放到WHERE子句里,让整个逻辑变成单条语句,更简洁:
$numbering = DB::update(DB::raw(" UPDATE table SET number = @a := @a + 1, table_number = @a + 1 WHERE @a := 0; ")); return $numbering;
这个写法的原理是利用WHERE子句先初始化@a为0,然后在SET里依次更新number和table_number,同样能实现一次更新完成两个字段的赋值。
另外提醒下:你代码里的number:= @a+1是笔误吗?MySQL里字段赋值用=即可,变量赋值用:=,所以正确的写法是number = @a := @a+1哦。
内容的提问来源于stack exchange,提问作者www.cahyonegoro.com

