Risk_key(策略KEY)中是记录所有的KEY,根据五个关键字段为main_type, conditions, interval, type,event来生成一个索引ID。其中interval字段允许为空,其它均不能为空。
背景介绍,新增策略时,根据上述五个关键字来生成一个新的KEY。如果两个累计策略,上述五个关键字相同,但是时长不同,此时会共用相同的KEY。
策略删除一条记录时,会根据上述五个关键字去搜索策略表,搜索到占用时就不允许删除,而搜索不到时才允许删除。
删除时查找索引ID的SQL如下:
SQL-1:
select ID,STRATEGY_NAME,_MAIN_TYPE,_CYCLE,_CONDITIONS,_EVENT, _INTERVAL,_TYPE,_DESCRIPTION, _MEMO,_STATUS,GMT_CREATE,GMT_MODIFY,OPERATOR_ID,MODIFY_OPERATOR fromrisk__strategy t1 where t1._STATUS = 'U' andt1.MAIN_TYPE = #MainType# andt1.CONDITIONS = #Conditions# andt1.EVENT = #Event# andt1.TYPE like CONCAT('%',#Type#,'%') <dynamic prepend="and"> <isNotNullprepend="and" property="Interval"> t1.INTERVAL= #Interval# </isNotNull> </dynamic>
SQL-2:
select ID,STRATEGY_NAME,_MAIN_TYPE,_CYCLE,_CONDITIONS,_EVENT, _INTERVAL,_TYPE,_DESCRIPTION, _MEMO,_STATUS,GMT_CREATE,GMT_MODIFY,OPERATOR_ID,MODIFY_OPERATOR fromrisk_strategy t1 where t1._STATUS = 'U' andt1.MAIN_TYPE = #MainType# andt1.CONDITIONS = #Conditions# andt1.EVENT = #Event# andt1.TYPE like CONCAT('%',#Type#,'%') and t1.INTERVAL = #Interval#
SQL-3:
select ID,STRATEGY_NAME,_MAIN_TYPE,_CYCLE,_CONDITIONS,_EVENT, _INTERVAL,_TYPE,_DESCRIPTION, _MEMO,_STATUS,GMT_CREATE,GMT_MODIFY,OPERATOR_ID,MODIFY_OPERATOR fromrisk_strategy t1 where t1.STATUS = 'U' andt1.MAIN_TYPE = #MainType# andt1.CONDITIONS = #Conditions# andt1.EVENT = #Event# andt1.TYPE like CONCAT('%',#Type#,'%') <dynamic prepend="and"> <isNotNullprepend="and" property="Interval"> t1.INTERVAL= #Interval# </isNotNull> <isNull prepend="and" property="Interval"> t1.INTERVAL IS NULL </isNull> </dynamic>
在risk_strategy(策略表)中,有两条策略,策略A与策略B相同,唯一不同的是_interval字段,表示时间段。A策略此处为空,B策略此处为15:00-20:00。
risk__strategy表中记录如下:
策略A:main_type = 11,conditions = 22,_type = 33, event=44,interval 为空,时长为2天。
策略B:main_type = 11,conditions = 22,type = 33, event=44,interval=15:00-20:00,时长为3天。
策略C:main_type = 11, conditions = 22, type = 33, event=44,interval 为空,时长为15天。
在risk_key(策略索引ID表)中,有两条索引ID,暂定义为索引A与索引B。
索引A:main_type = 11, conditions = 22, type = 33, event=44,interval 为空。
索引B:main_type = 11, conditions = 22, type = 33, event=44,interval=15:00-20:00。
其中策略A与策略C同时占用索引A,而策略B占用索引B。
那么请问先删除A与先删除B会有什么结果不同吗?
在SQL-1的情况下,先删除策略A,会去查询索引A有没有被占用,根据SQL-1的结果,自动生成的SQL如下:
select * from risk__strategy t1 where t1.STATUS = 'U' and t1.MAIN_TYPE = 11 and t1.CONDITIONS = 22 and t1.EVENT = 44 and t1.TYPE like CONCAT('%',33,'%')
因为INTERVAL字段为空,所以
and t1.INTERVAL = 15:00-20:00
此句SQL未被包含进去。查询出来的结果是策略B也在占用,导致未被使用的索引A未被删除。
实际上索引A应该被删除。
如果先删除策略B,则索引B会被删除掉,然后再删除策略A,索引A被删除,功能正常。就发现不了上述问题。
在SQL-2的情况下,先删除策略A,根据SQL-2的结果,自动生成的SQL如下:
select * from risk_strategy t1 where t1.STATUS = 'U' and t1.MAIN_TYPE = 11 and t1.CONDITIONS = 22 and t1.EVENT = 44 and t1.TYPE like CONCAT('%',33,'%') and t1.INTERVAL = null
删除索引A时,根据上述SQL去查询,由于t1.INTERVAL = null永远为假,因此查询出来的结果为始终没有累计策略占用,但是此时另外有一个策略C占用,没有查询不出来。导致不管有没有占用,都会直接被删除。
如果先删除策略B,那么会直接把索引B删除,再删除策略A时,那么会把索引A删除掉,那么就不会发现这个问题。另外如果此时再删除策略C,那么也能发现这个问题。
SQL-3为修复后正确的SQL!
上述的问题跟测试用例执行的顺序是有关系的,只有在特定的顺序下才能发现,是偶然的BUG或者几率性的BUG吗?
没有偶然的或者几率性的BUG,只是我们没有真正找到他们的规律,这个是个漫长的过程,加油,慢慢寻找BUG的本源。
这个BUG算是一个提醒,希望从现在开始,关注到SQL这层。