1、生产bug
这是一个A系统从B系统同步项目信息的job。
2、排查
后台报错:
java.sql.SQLException: ORA-01795: maximum number of expressions in a list is 1000
原因:in里面最多1000个值,如果in的括号里面超过了1000个值,就会报这个错误。
经查,sqlMapping里的sql确实是使用了 IN (不推荐在sql里使用in,没办法,这是前人写得)
那么为什么会一次性过来超过1000条数据呢?
RPC监控平台上,接口过来5019条数据。
同步的原理的是根据版本号:syncVersion
经查本系统A最大版本号为:1563874473
而另一个系统B中比A的最大版本号大的数据有5019条
为什么突然有这么多条数据呢?(正常情况下,一次job不可能有这么多条数据)
经询问,B系统的人,直接在数据库执行过sql,根据时间点,发现就是B系统的人执行过sql之后,导致了A系统的job报错。
经排查,发现B系统的sql改变了5018条数据,然后这5018条数据的版本号全部变为相同的了,(这其中还有个同步表_sync-table,此处忽略),加上, 这又是为什么呢?
3、原来,是因为触发器的存在
之所以想到是触发器的存在,是因为在前段时间,另一个项目拆库拆表的时候,搞过触发器问题
注意到触发器中,设定sync_version是取的当前时间,now(),mysql中的now(),只能精确到秒,当使用一条sql同时执行五千条数据时,是在几百ms内执行完,所以这就是为什么上文中,这五千多条数据的版本号相同的原因。
4、解决问题
把A系统中的最大版本号更新为合适的值(小于B系统的版本号的新增数据的最大值),再次执行job,成功。
5、聊聊 触发器
——什么是触发器?
触发器是一种特殊类型的存储过程,它由事件触发,而不是程序调用或手工启动。
当数据库有特殊的操作时,对这些操作由数据库中的事件来触发,自动完成这些SQL语句。
——触发器与存储过程的区别?
——触发器的作用:
(1) 增加安全性
(2) 利用触发器记录所进行的修改以及相关信息,跟踪用户对数据库的操作,实现审计。
(3) 维护哪些通过创建表时的声明约束不可能实现的复杂的完整性约束以及对数据库中特定事件进行监控与响应。
(4) 实现复杂的非标准的数据库相关完整性规则、同步实时地复制表中的数据
(5) 触发器是自动的,它们在对表的数据做了任何修改之后就会被激活。 例如,可以自动计算数据值,如果数据的值达到了一定的要求,则进行特定的处理。 以某企业财务管理为例,如果企业的资金链出现短缺,并且达到某种程度时,则发送警告信息。
——触发器相关sql
(1)创建
创建有一条执行语句的触发器:
create trigger trigger_name
before|after trigger_event
on table_name for each row trigger_stmt
创建包含多条执行语句的触发器
create trigger trigger_name
before|after trigger_event
on table_name for each row
begin
trigger_stmt
end
(2)查看: show triggers
(3)删除: drop trigger trigger_name
——根据SQL语句的不同,触发器可分为两类:DML触发器、DLL触发器
DML触发器是当数据库服务器发生数据操作语言事件时执行的存储过程,有After和Instead of两种触发器。After触发器是当数据被激活触发是在记录该表之后进行的一种触发器。 Instead of触发器是在记录变更之前,去执行触发器本身所定义的操作,而不是执行原来SQL语句里的操作。
DLL触发器是在响应数据定义语言事件时执行的存储过程。
——事前触发、事后触发的区别? 语句级触发、行级触发的区别?
事前触发发生在事件发生之前验证一些条件或进行有一些准备工作;
事后触发发生在事件发生之后,做收尾工作,保证事务的完整性。 而事前触发可以获得之前和新的字段值。
语句级触发可以在语句执行之前或之后执行,
行级触发在触发器所影响的每一行触发一次。
6、最后,给点建议:
小心触发器;
尽量少直接用sql操作生产数据库;
遇到生产bug,解决问题的思路很重要;
技术很重要,态度更重要