您好,登錄后才能下訂單哦!
大數(shù)據(jù)中如何解決雪花算法ID到前端之后精度丟失問(wèn)題,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。
最近公司的一個(gè)項(xiàng)目組要把以前的單體應(yīng)用進(jìn)行為服務(wù)拆分,表的ID主鍵使用Mybatis plus默認(rèn) 的雪花算法來(lái)生成。
快下班的時(shí)候,小伙伴跑過(guò)來(lái)找我,:“快給我看看這問(wèn)題,卡這卡了小半天了!”。連拉帶拽,連哄帶騙的把我拉到他的電腦前面。這位小伙伴在我看來(lái)技術(shù)不算是大牛,但經(jīng)驗(yàn)也很豐富了。他都卡了半天的問(wèn)題,應(yīng)該不是小問(wèn)題,如果我一時(shí)半會(huì)搞不定,真的是耽誤我下班了,所以我很不情愿的在他的位置坐了下來(lái)。
下面我把異常的現(xiàn)象給大家描述一下,小伙伴建了一張表,表的主鍵是id BigINT,用來(lái)存儲(chǔ)雪花算法生成的ID,嗯,這個(gè)沒(méi)有問(wèn)題!
CREATE TABLE user ( id BIGINT(20) NOT NULL COMMENT '主鍵ID', #其他字段省略 );
使用Long 類(lèi)型對(duì)應(yīng)數(shù)據(jù)庫(kù)ID數(shù)據(jù)。嗯,也沒(méi)有問(wèn)題,雪花算法生成的就是一串?dāng)?shù)字,Long類(lèi)型屬于標(biāo)準(zhǔn)答案!
[@Data](https://my.oschina.net/difrik) public class User { private Long id; //其他成員變量省略
在后端下斷點(diǎn)??吹綌?shù)據(jù)響應(yīng)以JSON響應(yīng)給前端,正常
{ id:1297873308628307970, //其他屬性省略 }
最后,這條數(shù)據(jù)返回給前端,前端接收到之后,修改這條數(shù)據(jù),后端再次接收回來(lái)。奇怪的問(wèn)題出現(xiàn)了:后端重新接收回來(lái)的id變成了:12978733086283000000,不再是1297873308628307970
我的第一感覺(jué)是,開(kāi)發(fā)小伙伴把數(shù)據(jù)給搞混了,張冠李戴了,把XXX的對(duì)象ID放到了YYY對(duì)象的ID上。所以,就按照代碼從前端到后端、從后端到前端調(diào)試跟蹤了一遍。
從代碼的邏輯角度上沒(méi)有任何問(wèn)題。這時(shí),我有點(diǎn)煩躁了,真的是耽誤我下班了!但開(kāi)工沒(méi)有回頭箭,既然坐下來(lái)了就得幫他解決,不然以后這隊(duì)伍怎么帶?想到這我又靜下心來(lái),開(kāi)始思考。
1297873308628300000 ---> 1297873308628307970
這兩個(gè)數(shù)長(zhǎng)得還挺像的,似乎是被四舍五入了。此時(shí)腦袋里面冒出一個(gè)想法,是精度丟失了么?哪里能導(dǎo)致精度丟失?
服務(wù)端都是Long類(lèi)型的id,不可能丟失
前端是什么類(lèi)型,JSON字符串轉(zhuǎn)js對(duì)象,接收Long類(lèi)型的是number
上網(wǎng)查了一下Number精度是16位(雪花ID是19位的),So:JS的Number數(shù)據(jù)類(lèi)型導(dǎo)致的精度丟失。問(wèn)題是找到了! 小伙伴投來(lái)敬佩的眼光,5分鐘就把這問(wèn)題發(fā)現(xiàn)了。可是發(fā)現(xiàn)了有什么用?得解決問(wèn)題?。?/p>
開(kāi)發(fā)小伙伴說(shuō):那我把所有的數(shù)據(jù)庫(kù)表設(shè)計(jì),id字段由Long類(lèi)型改成String類(lèi)型吧。我問(wèn)他你有多少?gòu)埍恚克f(shuō)100多張吧。
100多張表還有100多個(gè)實(shí)體類(lèi)需要改
還有各種使用到實(shí)體類(lèi)的Service層要改
Service等改完Controller層要改
關(guān)鍵的是String和Long都是常用類(lèi)型,他還不敢批量替換
小伙伴拿起電話打算訂餐,說(shuō)今晚的加班是無(wú)法避免了。我想了想說(shuō):你最好別改,String做ID查詢性能會(huì)下降,我再想想!后端A到前端B出現(xiàn)精度丟失,要么改前端,要么改后端,要么…… 。“哎哎,你等等先別訂餐,后端A到前端B你用的什么做的序列化?” 小伙伴告訴我說(shuō)使用的是Jackson,這就好辦了,Jackson我熟悉?。?/p>
解決思路:后端的ID(Long) ==> Jackson(Long轉(zhuǎn)String) ==> 前端使用String類(lèi)型的ID,前端使用js string精度就不會(huì)丟失了。 那前端再把String類(lèi)型的19位數(shù)字傳回服務(wù)端的時(shí)候,可以用Long接收么?當(dāng)然可以,這是Spring反序列化參數(shù)接收默認(rèn)支持的行為。
最終方案就是:前端用String類(lèi)型的雪花ID保持精度,后端及數(shù)據(jù)庫(kù)繼續(xù)使用Long(BigINT)類(lèi)型不影響數(shù)據(jù)庫(kù)查詢執(zhí)行效率。
剩下的問(wèn)題就是:在Spring Boot應(yīng)用中,使用Jackson進(jìn)行JSON序列化的時(shí)候怎么將Long類(lèi)型ID轉(zhuǎn)成String響應(yīng)給前端。方案如下:
[@Configuration](https://my.oschina.net/pointdance) public class JacksonConfig { [@Bean](https://my.oschina.net/bean) [@Primary](https://my.oschina.net/primary) @ConditionalOnMissingBean(ObjectMapper.class) public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { ObjectMapper objectMapper = builder.createXmlMapper(false).build(); // 全局配置序列化返回 JSON 處理 SimpleModule simpleModule = new SimpleModule(); //JSON Long ==> String simpleModule.addSerializer(Long.class, ToStringSerializer.instance); objectMapper.registerModule(simpleModule); return objectMapper; } }
小伙伴放下電話, 再次投來(lái)敬佩眼光?!白甙?,一起下班!”我和小伙伴說(shuō),小伙伴一路上一直問(wèn)我你是怎么學(xué)習(xí)的?我冠冕堂皇的說(shuō)了一些多想多學(xué)多問(wèn)之類(lèi)的話。 其實(shí)我心里在想:我是一個(gè)懶人,但我不能說(shuō)。能躺著絕不坐著,能自動(dòng)絕不手動(dòng),能打車(chē)絕不自己開(kāi)車(chē)。第一次就把事情做對(duì),才是省時(shí)省力做好的方法!這么多年的“懶”,決定了我需要去思考更多的“捷徑”,思考“捷徑”的過(guò)程是我不斷進(jìn)階的訣竅!
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。