前因
最近公司后端項(xiàng)目進(jìn)行了改造升級(jí),由之前的laravel5.6版本升級(jí)到了laravel5.8版本,升級(jí)后系統(tǒng)產(chǎn)生了不少sql執(zhí)行錯(cuò)誤,但是在老版本系統(tǒng)運(yùn)行的好好的,于是就產(chǎn)生了今日的扒坑之旅。
推薦:《laravel教程》
項(xiàng)目環(huán)境
老系統(tǒng)(linux + laravel5.6 + php7.2 + mysql5.7)
升級(jí)后新系統(tǒng)(linux +laravel5.8 + php7.2 + mysql5.7)
只單純升級(jí)了laravel框架版本,并無升級(jí)其他相關(guān)服務(wù)依賴.
但是卻出現(xiàn)大量的SQL執(zhí)行錯(cuò)誤,異常監(jiān)控如下:
分析過程
導(dǎo)致這段服務(wù)出錯(cuò)的是這樣的一段業(yè)務(wù)邏輯,下面通過一段demo來模擬.
$pivot?=?UserRole::firstOrCreate([ ????'user_id'?=>?3, ????'role_id'?=>?3, ]); $this->addRoleHistory($user,$pivot->id); dd($pivot->id);
在laravel5.6版本中這段代碼運(yùn)行起來毫無問題,但升級(jí)到5.8版本中就會(huì)引發(fā)大量的SQL執(zhí)行錯(cuò)誤,就像下面這樣.
laravel5.6: ????dd($pivot->id);?//10002 laravel5.8: ????dd($pivot->id);?//null
在5.6中保存中的數(shù)據(jù)還能正常獲取到ID,在5.8中怎么就不行了呢,于是馬上去查看了laravel5.8的發(fā)行說明,也沒有發(fā)現(xiàn)對(duì)Pivot模型取消獲取自增ID的改動(dòng),于是開始進(jìn)行5.8源碼查閱。。。
首先對(duì)5.6和5.8的firstOrCreate函數(shù)進(jìn)行了對(duì)比,發(fā)現(xiàn)無改動(dòng),代碼邏輯執(zhí)行無誤。
然后繼續(xù)翻閱model->save()函數(shù)的代碼
,發(fā)現(xiàn)不存在的數(shù)據(jù)是通過insertAndSetId該函數(shù)插入數(shù)據(jù)并設(shè)置主鍵ID
但insertAndSetId函數(shù)又是通過incrementing這樣的一個(gè)成員屬性來控制的,屬性的默認(rèn)值是true
當(dāng)這個(gè)屬性變更時(shí)就不會(huì)執(zhí)行者一步驟,難道這個(gè)成員屬性在被操作過了?
于是立馬查看了5.8的pivot模型源碼.
最終發(fā)現(xiàn)是5.8的在中間表Pivot class默認(rèn)將incrementing設(shè)置成了false,所以數(shù)據(jù)被成功插入,但是沒有設(shè)置插入后的主鍵ID,造成剩余服務(wù)崩潰,沒能正常運(yùn)行…
修復(fù)方案
在每個(gè)Pivot Class中重新覆蓋掉incrementing屬性值為true即可.
class?UserRole?extends?Pivot { ????public?$incrementing?=?true; ????protected?$fillable?=?[ ????????'user_id', ????????'role_id', ????]; }
修復(fù)后:
laravel5.8: ????dd($pivot->id);?//10003
后記
于是又去仔細(xì)看了一遍laravel5.7~laravel5.8發(fā)行說明,發(fā)現(xiàn)依然沒有提到這個(gè)改動(dòng)的原因,于是又去google了一遍,依然沒有找到這個(gè)梗的原因所在.
最后還是成功修復(fù)掉了該處改動(dòng)帶來的問題,也提醒了我們在后續(xù)版本升級(jí)時(shí)還是需要多注重UT的覆蓋及版本兼容改動(dòng)測試,多個(gè)維度來保證項(xiàng)目質(zhì)量。