這是一次很偶然的發現,連自己都覺得意外..............
背景:1.本宿舍樓浴室
2.一卡通校園卡以及讀卡收費器(自動感應)
3.刷卡規則,將一卡通卡片放在讀卡器正面,1秒左右自動讀取1元並開始放水,每4秒計費一次,每次
扣除1分錢。1元錢全部扣除或者再次刷卡都可將洗澡水停下。消費金額按照讀卡器扣除金額爲準。
研究:2張不同學生的卡片按照一定次序打卡的結果
時間:中午13點左右
一開始沒有想到這些問題,像平常一樣洗澡。突然覺得同學的卡能不能停下我的水呢?我就嘗試打了一下,結果計費器顯示從同學的卡片上扣除了我的計費器上的金額。心裏有些不安,然後用自己的卡打開龍頭,奇蹟出現了,我的卡顯示金額還是在剛剛消費之前的金額。我估計是把剛纔的消費都在同學的卡上扣除了。然後我想到了,對數據庫操作產生髒數據的推斷。於是,我想到了如下的策略(以髒數據問題作爲指導):
我的卡:A 我用的龍頭爲:L1
同學的卡:B 同學的龍頭:L2
1.用A卡使L1流水,開始計費,假設此時卡上有20元整。開始洗澡。
2.L1上的錢剩下0.05左右(馬上就要停水並對卡片A進行計費時),用A卡打開L2,然後迅速用A關上L1。然後,迅速關上L2。按照髒數據問題,可以知道,此時的讀卡器主動參與計費,等待計費結束,update數據庫扣除消費。這樣子,在L1上消費被當作髒數據從數據庫當中被L2的更新覆蓋了。也就是說,讀卡器的讀卡規則是,首先記錄A卡的餘額,然後開始計費。再次打卡將從餘額中扣除讀卡器上消費金額。從而L1,L2讀卡時的餘額應該是一樣的,但是2臺機器計費額是不同的,由於先後寫入的次序不同造成髒數據。
3.用A使L1流水,假設此時B當中只有1元(不足1元不能讀卡,否則就可以透支了,看來設計者想到了這一點)。用B卡停止L1流水。此時,L1寫回B卡中A卡數據。從而造成數據混亂,並可以作爲提高卡片餘額的“好方法”。與上面的想法不同,這裏髒數據的讀寫是在L1讀取並記錄A的餘額並在第二次打卡的時候就已經計算好餘額並寫回A當中作爲策略的。因此,B卡當中寫回的是A卡的數據。也就是說,不會產生2中的現象。但是也不能證明2中的問題可以因此解決。
結果:利用一卡通管理設備,從互聯網上查詢並計算金額卻發現,在中午消費的過程當中整個消費金額並沒有因爲試驗的原因而真正的減少。從消費次數來看,果真在消費過程當中卡片消費次數並不是像往常一樣順序增加,而是跳躍式的211 213 216........看來,消費確實存在一定的跳躍性,但是爲什麼金額不會因爲髒數據理論而減少或者有目的增加呢?
在仔細的對數據庫報表進行分析以後得到了一些結論,數據表內容如下:
2004/11/30 13:05:50 | 卡片消費 | 2004/11/30 13:17:55 | 23.00 | -0.79 | 22.21 | 水控子系統 | 220 | 正常 |
2004/11/30 13:00:23 | 卡片消費 | 2004/11/30 13:11:12 | 24.02 | -0.02 | 24.00 | 水控子系統 | 217 | 正常 |
2004/11/30 13:00:19 | 卡片消費 | 2004/11/30 13:11:08 | 23.60 | -0.58 | 23.02 | 水控子系統 | 216 | 正常 |
2004/11/30 12:51:50 | 卡片消費 | 2004/11/30 13:02:45 | 24.62 | -0.02 | 24.60 | 水控子系統 | 213 | 正常 |
2004/11/30 12:51:35 | 卡片消費 | 2004/11/30 13:02:30 | 24.85 | -0.23 | 24.62 | 水控子系統 | 211 | 正常 |
2004/11/30 12:51:13 | 卡片消費 | 2004/11/30 13:02:09 | 24.00 | -0.15 | 23.85 | 水控子系統 | 210 | 正常 |
2004/11/30 12:49:51 | 卡片消費 | 2004/11/30 13:00:47 | 24.01 | -0.01 | 24.00 | 水控子系統 | 208 | 正常 |
2004/11/30 12:48:43 | 卡片消費 | 2004/11/30 12:59:40 | 25.06 | -0.05 | 25.01 | 水控子系統 | 205 | 正常 |
2004/11/30 12:47:37 | 卡片消費 | 2004/11/30 12:58:35 | 25.19 | -0.13 | 25.06 | 水控子系統 | 203 | 正常 |
2004/11/30 12:44:18 | 卡片消費 | 2004/11/30 12:55:18 | 25.48 | -0.29 | 25.19 | 水控子系統 | 201 | 正常 |
但是從碼的角度來講,可以看到這個消費系統當中時間是主碼,因爲當時間不同消費金額會產生差別,靠這種機制完成計費以及對卡消費次序的正確紀錄,避免了髒數據的讀寫。但是,從另一方面不太理解,如果消費次數沒有區別的功能,爲什麼還有這項一眼就能看出問題的數據項存在呢?
就此問題,我們進一步想,如果使用時間作爲主碼,那麼消費前後的2個時間怎麼作爲主碼?如果1次消費從另一次消費當中,怎麼辦呢?比方說用A先後打開L1 L2呢?這些就不得而知了。
但是有一點可以肯定,在計費機器方面有可能存在編號問題,每一筆消費都是按照消費機器的編號區別的,但是這樣子的矛盾在於如果我用B卡結束A卡的消費,數據庫會怎樣紀錄數據呢?但無論怎麼說,這個推斷的說服力最大。
還有一個現象,就是如果你在中午消費,比方說去餐廳就餐。但是你的清算結果應該是在下午才能查詢出來,在這中間的延時很可能是暫存在計費機器當中造成的。那麼爲什麼在數據的update得時候沒有機器編號在裏面呢?如果錯誤的消費過後如何查詢並退回錯誤操作的那部分錢呢?
也許這樣的分佈式系統當中還有很多我沒有學到的策略和機制。所謂人外有人,山外有山啊!