事情是这样的,最近在重构旧项目,项目中有一段逻辑调用了Oracle的存储过程,类似于这样:
这段存储过程的SQL是在数据库里面的,非常长,我是很不喜欢在程序中使用存储过程的,这些逻辑也可以放在程序中啊。看不过眼就把这段长长的SQL复制到XML中了, 就成了这样:
这是insert,还有update:
太长了还用了begin/end就都截图了一部分 。可以看出来这段存储过程执行的时候是不需要任何参数的,所以这里<update>和<insert>标签页没有写parameterType,当然mapper中对应的方法页没有传任何参数,就想这样:
想着这样应该没有问题了,一执行却报错了,看了一眼异常栈信息:
通过异常栈信息可以看出来是报了空指针,而且可以看出来项目中用了mybatis-plus, 定位到了抛出异常的方法MybatisDefaultParameterHandler.processBatch(),看一下这个方法:
这是一个自动填充主键ID的一个方法,这对Orcale是很实用的 ,因为Oracle是不可以设置主键自增,而MybatisPlus提供继承MetaObjectHandler类的这种方法去自动填充主键,具体怎么操作后面会说,先说这次的问题出在哪里。
现在有insert类型的SQL,而且都是没有任何参数的,所以这里isFill=true,由于没有参数,parameterObject就成了null,于是getParameters(parameterObject)返回的就是null,即parameters为null,不满足null!=parameters的条件走了下面的else分支,但是这时候parameterObject也是null啊,所以这里的parameterObject.getClass()就报了空指针NullPointerException异常。update类型的SQL也是同理,不过好在update类型的SQL还有一个条件判断即metaObjectHandler.openUpdateFill(),可以把这个理解成一个开关,还可以控制update类型的SQL是不是需要自动填充,只要isFull为false也不会有什么问题,这个开关也是通过继承MetaObjectHandler类来控制,待会和如何自定义主键自增一起说。
然后这里的insert类型的SQL就没有这种开关控制了,MybatisPlus有很多jar包,这个项目中用的是com.baomidou.mybatisplus,也就是说在这个里面,只要是insert类型的SQL没有任何参数,就比如我遇到的这个场景,这里就会空指针,太现实了叭。
然后说一下如何通过继承MetaObjectHandler类来控制update类型的SQL是否自动填充的开关和自定义填充主键的方法,很简单如图:
就是继承MetaObjectHandler分别重写insertFill方法自定义主键填充逻辑,重写openUpdateFill方法控制update类型的SQL是否自动填充,这个MetaObjectHandler中还有其他方法比如updateFill()等可以去了解一下。
最后说一下我是怎么解决今天遇到的问题的,对于update类型的SQL就是重写了这个openUpdateFill()方法,这就不说了,有意思的是对于insert类型的SQL,我给它强行加了一个参数,虽然SQL执行的时候并不需要.......如图:
虽然有点蠢,不过问题解决了,就这样吧。