記一個玄學(xué)bug

Part I

寫了一段代碼要批量導(dǎo)出數(shù)據(jù),格式如下,

<data>
    <card_no>************</card_no>
    <id>16111710001385</id>
    <mobile_no>*********</mobile_no>
    <pid_code>************</pid_code>
    <pid_type>01</pid_type>
    <real_name>測試</real_name>
    <status>1</status>
    <user_id>000000000000099</user_id>
</data>

然后經(jīng)過檢查發(fā)現(xiàn)大量數(shù)據(jù)<real_name>字段為空,首先懷疑是數(shù)據(jù)庫問題,執(zhí)行sql測試,發(fā)現(xiàn)可以取得正常結(jié)果,數(shù)據(jù)庫中有正常的密文存儲結(jié)果,

sql執(zhí)行結(jié)果.png

并且結(jié)果數(shù)量與xml文件中數(shù)量一致,說明提取的sql肯定沒問題,然后排查結(jié)果集映射,跟real_name有關(guān)的映射如下:

<result property="realName" column="user_name" />

經(jīng)過仔細驗證也沒問題(其實這里有點不自信,浪費了好久時間).
至此我們已經(jīng)基本排除了數(shù)據(jù)源和model層的問題(我以為),隨后進下一層進行排查.

Part II

我注意到除了大量為空的數(shù)據(jù)以外,還有少量亂碼,由于realName都是中文,所以懷疑是編碼問題,業(yè)務(wù)流程是從數(shù)據(jù)庫取值存到一個model的List里,再將List遍歷逐個轉(zhuǎn)化為XML元素,依次寫入文件流,最終將文件流保存到本地文件中.
那么可以看出最容易出問題的兩個環(huán)節(jié),一個是轉(zhuǎn)換為xml時候的編碼,一個是寫入文件流時候的編碼.(伏筆2)
檢查設(shè)置如下

m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");

多次測試以后發(fā)現(xiàn)并沒有問題.

Part III

隨后進行單元測試,直接運行用例,發(fā)現(xiàn)遍歷列表輸出無誤,但是當遍歷列表后再進入xml轉(zhuǎn)換時出現(xiàn)問題.此時進入debug,徹底進入玄學(xué)

@Test
    public void singleXMLTest(){

        List<UserCardInf> list = backupDao.selectUserCardInf("20161116000000");
        for(UserCardInf card:list){
            System.out.println(card);
        }
//      BackupUtils.XMLIO(list,
//              BackupUtils.getFileName(BackupUtils.USER_CARD_INF_NAME),
//              BackupUtils.USER_CARD_INF_NAME);
//      
    }

進入debug后,點斷點進入遍歷,發(fā)現(xiàn)每個card的realName全部為空,這時在UserCardInf里面加入斷點

@XmlElement(name="real_name")
    public String getRealName() {   
        realName=DecodeAndEncodeUtil.desDecrypt(realName);
        return realName==null?"":realName;
    }

發(fā)現(xiàn)進入get方法以后realName直接為空,百思不得其解,我決定去上個廁所.

這個決定讓我徹底走上了玄學(xué)的道路.

等我回來以后,隨手debug一次,一路F6,發(fā)現(xiàn)居然打印出了正確結(jié)果

201611171000811:|6214*********6575:|182******557:|測試:|01:|510*********7999:|1:|

我以為我的鍵盤成精,有個傳說中的鍵盤姑娘什么的,畢竟不能辜負我的飲料餅干經(jīng)常分它一部分,還經(jīng)常給它洗澡,而且鍵盤出身好,大戶人家(F廠),優(yōu)質(zhì)內(nèi)涵(原廠軸)成精必然是個美女,我想還是可以接受的...因此我單方面宣布其實鍵盤自動幫我改正了.
然而經(jīng)過之前跟別人討論時候的截圖仔細對比,發(fā)現(xiàn)代碼沒有變化過.
那么從科學(xué)的角度出發(fā),我們可以考慮其他變量,首先快速debug一遍,一路斷點直接F6,發(fā)現(xiàn)可以正常打印,這時我懷疑是在我斷點期間其他線程操作了我的變量,導(dǎo)致沒有正確結(jié)果.這時我很好奇?zhèn)魅氲闹?所以將鼠標指向card,這時第一個card已經(jīng)打印完畢,結(jié)果正確,但是第二個card進入后依然為null,這時我意識到可能是我的鼠標指向操作影響了屬性值,于是我在getRealName()方法上加了斷點,如果調(diào)用get方法,必然會跳入斷點,從而證實我的猜想.
而結(jié)果令我非常失望,結(jié)果依然為null,并且沒有跳入斷點.所以這時我進行了大量重復(fù)試驗,發(fā)現(xiàn)其他操作因素(時間/快慢/列表長度)都不影響結(jié)果,唯一影響結(jié)果的就是鼠標指向,那么我的鼠標又不是金手指可以直接擦寫內(nèi)存,我是如何影響realName屬性的呢,我再次在getRealName方法上做文章,這次我加入了System.out.println(realName),并且采用了之前是亂碼的那條數(shù)據(jù),發(fā)現(xiàn)其規(guī)律是 密文->明文->亂碼->亂碼->null,因此我判斷一定是我的鼠標指向操作調(diào)用了get方法,使得其多次調(diào)用解密操作,使得數(shù)據(jù)結(jié)果有誤,最終由于數(shù)據(jù)太短無法解密返回null,于是我加上調(diào)用解密方法的日志,發(fā)現(xiàn)我每次鼠標指向果然會調(diào)用解密操作.
最后我將get方法修改如下:

private int i=0;
    @XmlElement(name="real_name")
    public String getRealName() {
        if(nameFlag){
            realName = DecodeAndEncodeUtil.desDecrypt(realName);
            nameFlag=false;
        }
        System.out.println("調(diào)用get@"+this.hashCode()+":"+i++);
        return realName==null?"":realName;
    }

我發(fā)現(xiàn)每次鼠標指向都是IDE在后臺自動調(diào)用了get方法,所以i的數(shù)量在依次變大,同時不會跳入get方法的斷點...
最終測試結(jié)果打印日志:

調(diào)用get@20477080:1
調(diào)用get@17485453:1
調(diào)用get@20477080:2
調(diào)用get@17485453:2
調(diào)用get@20477080:3
調(diào)用get@17485453:3
調(diào)用get@20477080:4
調(diào)用get@17485453:4
調(diào)用get@20477080:5
調(diào)用get@17485453:5
調(diào)用get@20477080:6
201611171000811:|621**************685:|182*******57:|測試:|01:|51***********99:|1:|
調(diào)用get@17485453:6
201611171000811:|621***********04:|1822*********57:|測試:|01:|5108****************99:|1:|
databackup結(jié)束
databackup執(zhí)行時間為:28718 ms-------------

經(jīng)過一下午的努力,終于用科學(xué)破解了玄學(xué)了秘密,其實有很多次提前發(fā)現(xiàn)問題的關(guān)鍵,但是一方面是對自己的代碼沒自信,浪費了大量時間復(fù)查,一方面是對別人的代碼太自信,導(dǎo)致了我一開始堅持認為調(diào)用解密方法不會出問題,更不可能返回null..

雖然玄不救非,氪不改命,但是我用科學(xué)的方法破解了玄學(xué),所以我經(jīng)過科學(xué)推理發(fā)現(xiàn)我遲早要出循環(huán)儀式護肩...
謝謝大家收看...我下班了...讓我們拭目以待

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末某宪,一起剝皮案震驚了整個濱河市蹈胡,隨后出現(xiàn)的幾起案子风瘦,更是在濱河造成了極大的恐慌,老刑警劉巖傻盟,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嚷量,居然都是意外死亡取逾,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門箕母,熙熙樓的掌柜王于貴愁眉苦臉地迎上來储藐,“玉大人俱济,你說我怎么就攤上這事「撇” “怎么了蛛碌?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長辖源。 經(jīng)常有香客問我蔚携,道長,這世上最難降的妖魔是什么克饶? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任酝蜒,我火速辦了婚禮,結(jié)果婚禮上矾湃,老公的妹妹穿的比我還像新娘亡脑。我一直安慰自己,他們只是感情好洲尊,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布远豺。 她就那樣靜靜地躺著奈偏,像睡著了一般坞嘀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惊来,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天丽涩,我揣著相機與錄音,去河邊找鬼裁蚁。 笑死矢渊,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的枉证。 我是一名探鬼主播矮男,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼室谚!你這毒婦竟也來了毡鉴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤秒赤,失蹤者是張志新(化名)和其女友劉穎猪瞬,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體入篮,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡陈瘦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了潮售。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痊项。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡锅风,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鞍泉,到底是詐尸還是另有隱情遏弱,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布塞弊,位于F島的核電站漱逸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏游沿。R本人自食惡果不足惜饰抒,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望诀黍。 院中可真熱鬧袋坑,春花似錦、人聲如沸眯勾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吃环。三九已至也颤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間郁轻,已是汗流浹背翅娶。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留好唯,地道東北人竭沫。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像骑篙,于是被迫代替她去往敵國和親蜕提。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容