
這是Mysql的binlog日志,其中,third_logistics_no、order_no都應(yīng)該是字符串類型,但是這里執(zhí)行的時候變成了數(shù)值型;
業(yè)務(wù)邏輯是:程序在進來的時候首先會鎖住該訂單號的物流記錄,然后執(zhí)行更新語句;
然而在執(zhí)行更新語句的時候,本來應(yīng)該是字符串類型的參數(shù)卻變成了數(shù)值型,給表列賦值與表類型不符合時,MySql底層的優(yōu)化器發(fā)揮作用,會做一個強制類型轉(zhuǎn)化,此時能正常操作,但會導(dǎo)致行鎖升級為表鎖;
重現(xiàn)場景如下:
session1:begin;
session2:begin;
session1:select * from orders where order_no = '001' for update;
session2:select * from orders where order_no = '002' for update;
session1:update orders set order_status = 1 where order_no = 001;// session2上面已經(jīng)獲取了002的鎖,產(chǎn)生了鎖等待,因為MySQL強制類型轉(zhuǎn)換,行鎖變成了表鎖;
session2:update orders set order_status = 2 where order_no = 002;// 執(zhí)行就報了死鎖;
總結(jié):session1等session2的鎖,session2等session1的鎖,同時你等我的鎖,我等你的鎖,然后就死鎖了;


導(dǎo)致這個結(jié)果的原因是因為,sql語句的拼接中使用的是字符串拼接,寫法為:s""" update orders set order_no = ${request} """ 這個寫法
總結(jié)此次教訓(xùn),做了兩個實驗,如下:

可以看出,雖然我們定義的參數(shù)都是字符串類型,但是由于我們本身的寫法就是scala的字符串拼接,位于scala-lang包下的StringContext,在字符串處理的過程中,這個空串和引號直接被去掉了,得出的sql語句語法上就是錯誤的

正確的寫法應(yīng)該是用scala-sql,同樣的參數(shù),也是字符串類型,語句和參數(shù)應(yīng)該是這樣分開做兩次封裝的,傳入的參數(shù)是什么類型,執(zhí)行的語句中參數(shù)就是什么類型;
綜上,執(zhí)行的sql語句要嚴(yán)格按照標(biāo)準(zhǔn)規(guī)范來寫,不同的東西效果肯定不一樣。