波波給我說,我們driver_record表數據不在了一部分,就是一個帳套的數據,其他帳套的數據都還在,時間大約是2019年5月22日下午3點多。
我首先想,我們是同一張表用了一個字段叫帳套ID來區分數據的,這一個帳套的全部數據掉了,人爲誤操作數據庫的可能性較小,程序bug的可能性較大。
既然是程序bug,那麼今天有沒有刪除這個表數據的sql執行過呢?我用下面的語句查詢了一下:
SELECT
sql_text,sql_fullText,last_load_time,first_load_time,module
FROM
v$sqlarea b
WHERE
last_load_time >= to_date('2019-05-22' ,'yyyy-mm-dd')
and
last_load_time <= to_date('2019-05-22 18' ,'yyyy-mm-dd hh24')
AND (sql_text LIKE '%DELETE%'
or
sql_text LIKE '%delete%'
)
AND (sql_text LIKE '%driver_record%'
or
sql_text LIKE '%DRIVER_RECORD%'
)
AND ROWNUM < 10
發現查詢結果爲:
發現了這一條sql:
DELETE FROM driver_record WHERE id = :1
看時間端不在今天,但是連接端是JDBC Thin Client,說明是程序連接的這個sql,不是數據庫工具連接的。
到這裏,我蒙圈了,沒有刪除全部數據的sql啊。我繼續想,既然可能是程序bug,那麼就可能循環刪除掉所有的記錄。
看sql 的樣式,應該是調用了平臺根據主鍵刪除的方法。
我在eclipse中查詢driverRecordMapper.deleteByPrimaryKey,找到了我們的CustomerReservationMateralServiceImpl類下面的這段代碼
DriverRecord dr = new DriverRecord();
dr.setDriverName(req.getDriverName());
dr.setDriverIdcard(req.getIdCard());
dr.setPhoneNum(req.getPhone());
List<DriverRecord> drs = driverRecordMapper.selectDriverBySoming(dr);
//如果 司機 身份證(駕駛證) 車牌沒有匹配過,直接新增
if (Utils.isEmpty(drs)) {
DriverRecord driver = new DriverRecord();
driver.setAccountId(UserContext.getAccountId());
driver.setDriverCarno(req.getCarNo());
driver.setDriverName(req.getDriverName());
driver.setDriverIdcard(req.getIdCard());
driver.setPhoneNum(req.getPhone());
driverRecordMapper.insertSelective(driver);
}
else {
for (int i = 0;i<drs.size();i++) {
drs.get(0).setDriverName(req.getDriverName());
driverRecordMapper.updateByPrimaryKeySelective(drs.get(0));
if (i != 0) {
driverRecordMapper.deleteByPrimaryKey(drs.get(i).getId());
}
}
}
果然有我害怕的循環和刪除
逆向繼續推導,如果是循環刪除掉了,那麼循環的對象應該是查詢出了該表該帳套的所有記錄。
我繼續查看mapper中對應的查詢方法:
<select id="selectDriverBySoming" parameterType="com.jwell.mms.cc.entity.DriverRecord" resultMap="BaseResultMap">
SELECT
*
FROM DRIVER_RECORD dr
<where>
dr.ACCOUNT_ID = #{accountId}
<if test="driverCarno != null and driverCarno !='' ">
and dr.DRIVER_CARNO = #{driverCarno}
</if>
<if test="driverName != null and driverName !='' ">
and dr.DRIVER_NAME = #{driverName}
</if>
<if test="driverIdcard != null and driverIdcard !='' ">
and dr.DRIVER_IDCARD = #{driverIdcard}
</if>
<if test="phoneNum != null and phoneNum !='' ">
and dr.PHONE_NUM = #{phoneNum}
</if>
</where>
order by dr.CREATE_TIME DESC
</select>
其實不看我都知道,按照我們的代碼習慣,經常查詢條件不傳遞就是查詢整個帳套的數據的,看着這段sql腳本模版,我猜測可能有一次全部查詢。於是我又繼續到數據庫找痕跡:
select first_load_time,last_load_time,sql_text,sql_fulltext from v$sqlarea where sql_FULLtext LIKE '%FROM DRIVER_RECORD dr%' AND first_load_time >= '2019-05-22'
查詢結果是疑似事件時間真的有一次全表查詢。。。。跟我推測一致。
再返回來看代碼,可能是前臺傳遞的參數沒有,也沒有檢查,導致了本次全表查詢並循環刪除。找到bug了,就好辦了,洗洗睡。