波波给我说,我们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 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
果然有我害怕的循环和删除
逆向继续推导,如果是循环删除掉了,那么循环的对象应该是查询出了该表该帐套的所有记录。
我继续查看mapper中对应的查询方法:
其实不看我都知道,按照我们的代码习惯,经常查询条件不传递就是查询整个帐套的数据的,看着这段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了,就好办了,洗洗睡。