mybatis 有時(shí)update語(yǔ)句執(zhí)行無(wú)效的解決方案
項(xiàng)目里mybatis有時(shí)update語(yǔ)句執(zhí)行無(wú)效
公司測(cè)試人員在測(cè)試的時(shí)候發(fā)現(xiàn),在積分系統(tǒng),消費(fèi)產(chǎn)生了積分,有時(shí)候,卻不能加到用戶累計(jì)積分上去。
明明積分流水記錄跟用戶積分的增加在一個(gè)事務(wù)當(dāng)中的。積分流水記錄生成成功,偏偏用戶積分沒(méi)有加上去?奇了怪了。
加積分的代碼是:
tMemberPointMapper.updateByPrimaryKeySelective(tMemberPoint);
然后在相應(yīng)的位置,加了日志,記錄更新語(yǔ)句前后的對(duì)比。
測(cè)試人員再次發(fā)現(xiàn)問(wèn)題時(shí)查看了日志,日志顯示更新語(yǔ)句執(zhí)行后的對(duì)象確實(shí)是有累加過(guò)積分的。為什么數(shù)據(jù)庫(kù)表中的值就是沒(méi)變呢?
于是百度啊,這種情況百度的結(jié)果比較少,有的說(shuō)是mybatis的版本的問(wèn)題?個(gè)人感覺(jué)不太可能,因?yàn)檫@個(gè)mybatis版本在很多項(xiàng)目是使用,都沒(méi)出過(guò)問(wèn)題。事務(wù)也是測(cè)試過(guò),有異常能夠回滾。
后來(lái)冷靜下來(lái)想了想出現(xiàn)問(wèn)題的時(shí)機(jī)。測(cè)試人員在消費(fèi)操作過(guò)后,會(huì)立刻點(diǎn)查看用戶積分的界面。這時(shí)會(huì)調(diào)獲取用戶積分信息的接口。因?yàn)檫@個(gè)接口,不僅僅是查詢,因?yàn)榈燃?jí)維持機(jī)制(過(guò)一定的周期,要扣掉一部分積分), 它在查詢前,對(duì)用戶積分有修改的操作。所在,查詢用戶積分的接口,也處在非只讀的事務(wù)中。
當(dāng)兩個(gè)對(duì)同條用戶積分記錄操作的事務(wù)同時(shí)執(zhí)務(wù)(InnoDb的行級(jí)鎖,排它鎖),由于,mysql的默認(rèn)隔離級(jí)別是repeatable-read,事務(wù)A和事務(wù)B,讀到數(shù)據(jù)為a,后事務(wù)B修改了數(shù)據(jù)為b,提交了,而事務(wù)A再執(zhí)行修改操作,又會(huì)把數(shù)據(jù)b修改為數(shù)據(jù)a。這就出現(xiàn)了,題中所述的,偶爾出現(xiàn)update語(yǔ)句執(zhí)行無(wú)效的假象。
解決辦法
悲觀鎖 在查詢語(yǔ)句后加 for update ,鎖住事務(wù)中,查詢用戶積分的語(yǔ)句。
<select id="selectByExample" resultMap="BaseResultMap" parameterType="com.ice.pojo.f3.TMemberPointExample" > select <if test="distinct" > distinct </if> <include refid="Base_Column_List" /> from t_member_point <if test="_parameter != null" > <include refid="Example_Where_Clause" /> </if> <if test="orderByClause != null" > order by ${orderByClause} </if> for update </select>
執(zhí)行update語(yǔ)句后,數(shù)據(jù)沒(méi)有被更新,也沒(méi)有報(bào)錯(cuò)
記錄一下今天遇到的一個(gè)問(wèn)題:
問(wèn)題描述
執(zhí)行update語(yǔ)句后,數(shù)據(jù)沒(méi)有被更新,也沒(méi)有報(bào)錯(cuò)
詳細(xì)情況
通過(guò)傳參的方式,在控制臺(tái)打印出的sql語(yǔ)句;將sql語(yǔ)句拷貝到數(shù)據(jù)庫(kù)執(zhí)行也是OK
解決辦法
百思不得其解,到底問(wèn)題出在了那里?
所以,試了很多方法,最后才發(fā)現(xiàn)某一個(gè)字段的問(wèn)題;但是從控制臺(tái)打印的sql語(yǔ)句來(lái)看,參數(shù)值也是OK的??;
然后我嘗試將mapper中sql語(yǔ)句的參數(shù)寫成控制臺(tái)打印出來(lái)的參數(shù),直接確定下來(lái),運(yùn)行,發(fā)現(xiàn)也是OK的,那么確定是這個(gè)參數(shù)問(wèn)題了;
但是映射啥的都沒(méi)問(wèn)題,所以問(wèn)題就有可能在數(shù)據(jù)庫(kù)存的這個(gè)字段的長(zhǎng)度問(wèn)題了,最后發(fā)現(xiàn)數(shù)據(jù)庫(kù)該字段的長(zhǎng)度長(zhǎng)于傳的參數(shù)的值,而且在實(shí)體類中使用trim()對(duì)屬性值做了處理,所以問(wèn)題就在這里,修改一下就好了。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
基于SpringBoot+Redis的Session共享與單點(diǎn)登錄詳解
這篇文章主要介紹了基于SpringBoot+Redis的Session共享與單點(diǎn)登錄,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07springboot 設(shè)置CorsFilter跨域不生效的解決
這篇文章主要介紹了springboot 設(shè)置CorsFilter跨域不生效的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11