ShardingSphere导致的NPE

1. 项目背景

工程内使用shardingsphere支持分库分表,上层使用的MybatisPlus,有一张表的操作总是报NullPointException。

2. 异常堆栈

### SQL: INSERT INTO t_tg_message  ( update_id, from_id, from_user_name, chat_id, type, data, text, create_time, deleted )  VALUES  ( ?, ?, ?, ?, ?, ?, ?, ?, ? )
### Cause: java.lang.NullPointerException
        at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:92) ~[mybatis-spring-2.0.5.jar!/:2.0.5]
        at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:440) ~[mybatis-spring-2.0.5.jar!/:2.0.5]
        at com.sun.proxy.$Proxy141.insert(Unknown Source) ~[?:?]
        at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:271) ~[mybatis-spring-2.0.5.jar!/:2.0.5]
        at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:60) ~[mybatis-plus-core-3.4.0.jar!/:3.4.0]
        at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) ~[mybatis-plus-core-3.4.0.jar!/:3.4.0]
        at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) ~[mybatis-plus-core-3.4.0.jar!/:3.4.0]
        at com.sun.proxy.$Proxy298.insert(Unknown Source) ~[?:?]
        at com.keyniu.user.web.tg.interceptors.impl.RecordInterceptor.appendMessage(RecordInterceptor.java:83) ~[classes!/:?]
        at com.keyniu.user.web.tg.interceptors.impl.RecordInterceptor.process(RecordInterceptor.java:40) ~[classes!/:?]
        at com.keyniu.user.web.tg.interceptors.Interceptor.intercept(Interceptor.java:13) ~[classes!/:?]
        at com.keyniu.user.web.tg.interceptors.InterceptorChain.process(InterceptorChain.java:37) ~[classes!/:?]
        at com.keyniu.user.web.tg.tgBot.onUpdateReceived(tgBot.java:70) ~[classes!/:?]
        at java.util.ArrayList.forEach(ArrayList.java:1541) ~[?:?]
        at org.tg.tgbots.meta.generics.LongPollingBot.onUpdatesReceived(LongPollingBot.java:27) ~[tgbots-meta-6.0.1.jar!/:?]
        at org.tg.tgbots.updatesreceivers.DefaultBotSession$HandlerThread.run(DefaultBotSession.java:317) ~[tgbots-6.0.1.jar!/:?]
Caused by: org.apache.ibatis.exceptions.PersistenceException:
### Error updating database.  Cause: java.lang.NullPointerException
### The error may exist in com/keyniu/out/mapper/TgMessageMapper.java (best guess)
### The error may involve com.keyniu.user.persist.thirdparty.mapper.TgMessageMapper.insert-Inline
### The error occurred while setting parameters
### SQL: INSERT INTO t_tg_message  ( update_id, from_id, from_user_name, chat_id, type, data, text, create_time, deleted )  VALUES  ( ?, ?, ?, ?, ?, ?, ?, ?, ? )
### Cause: java.lang.NullPointerException
        at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30) ~[mybatis-3.5.5.jar!/:3.5.5]
        at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:199) ~[mybatis-3.5.5.jar!/:3.5.5]
        at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:184) ~[mybatis-3.5.5.jar!/:3.5.5]
        at jdk.internal.reflect.GeneratedMethodAccessor312.invoke(Unknown Source) ~[?:?]
        at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
        at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
        at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:426) ~[mybatis-spring-2.0.5.jar!/:2.0.5]
        ... 14 more
Caused by: java.lang.NullPointerException
        at org.antlr.v4.runtime.tree.AbstractParseTreeVisitor.visit(AbstractParseTreeVisitor.java:18) ~[antlr4-runtime-4.7.2.jar!/:4.7.2]
        at org.apache.shardingsphere.sql.parser.mysql.visitor.impl.MySQLDMLVisitor.visitInsert(MySQLDMLVisitor.java:147) ~[shardingsphere-sql-parser-mysql-4.1.1.jar!/:4.1.1]
        at org.apache.shardingsphere.sql.parser.mysql.visitor.impl.MySQLDMLVisitor.visitInsert(MySQLDMLVisitor.java:127) ~[shardingsphere-sql-parser-mysql-4.1.1.jar!/:4.1.1]
        at org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser$InsertContext.accept(MySQLStatementParser.java:1090) ~[shardingsphere-sql-parser-mysql-4.1.1.jar!/:4.1.1]
        at org.antlr.v4.runtime.tree.AbstractParseTreeVisitor.visit(AbstractParseTreeVisitor.java:18) ~[antlr4-runtime-4.7.2.jar!/:4.7.2]
        at org.apache.shardingsphere.sql.parser.SQLParserEngine.parse0(SQLParserEngine.java:80) ~[shardingsphere-sql-parser-engine-4.1.1.jar!/:4.1.1]
        at org.apache.shardingsphere.sql.parser.SQLParserEngine.parse(SQLParserEngine.java:61) ~[shardingsphere-sql-parser-engine-4.1.1.jar!/:4.1.1]
        at org.apache.shardingsphere.underlying.route.DataNodeRouter.createRouteContext(DataNodeRouter.java:97) ~[shardingsphere-route-4.1.1.jar!/:4.1.1]
        at org.apache.shardingsphere.underlying.route.DataNodeRouter.executeRoute(DataNodeRouter.java:89) ~[shardingsphere-route-4.1.1.jar!/:4.1.1]
        at org.apache.shardingsphere.underlying.route.DataNodeRouter.route(DataNodeRouter.java:76) ~[shardingsphere-route-4.1.1.jar!/:4.1.1]
        at org.apache.shardingsphere.underlying.pluggble.prepare.PreparedQueryPrepareEngine.route(PreparedQueryPrepareEngine.java:54) ~[shardingsphere-pluggable-4.1.1.jar!/:4.1.1]
        at org.apache.shardingsphere.underlying.pluggble.prepare.BasePrepareEngine.executeRoute(BasePrepareEngine.java:96) ~[shardingsphere-pluggable-4.1.1.jar!/:4.1.1]
        at org.apache.shardingsphere.underlying.pluggble.prepare.BasePrepareEngine.prepare(BasePrepareEngine.java:83) ~[shardingsphere-pluggable-4.1.1.jar!/:4.1.1]
        at org.apache.shardingsphere.shardingjdbc.jdbc.core.statement.ShardingPreparedStatement.prepare(ShardingPreparedStatement.java:183) ~[sharding-jdbc-core-4.1.1.jar!/:4.1.1]
        at org.apache.shardingsphere.shardingjdbc.jdbc.core.statement.ShardingPreparedStatement.execute(ShardingPreparedStatement.java:143) ~[sharding-jdbc-core-4.1.1.jar!/:4.1.1]
        at jdk.internal.reflect.GeneratedMethodAccessor232.invoke(Unknown Source) ~[?:?]
        at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]

3. 问题定位

一开始是怀疑某个参数字段为空了,反复检查后确定参数都正确设置。表对应的实体类如下:

@Data
@Builder
@TableName("t_tg_message")
public class TgMessageEntity {
    @TableId(type = IdType.AUTO)
    private Long id;
    private Integer updateId;
    private Long fromId;
    private String fromUserName;
    private Long chatId;
    private String type;
    private String data;
    private String text;
    private Date createTime;
    private Integer deleted;
}

打开MybatisPlus源码抛异常的位置, DEBUG后确定executor、ms、parameter都不是空,才开始关注到root cause,其实是shardingsphere抛出的
在这里插入图片描述

看异常堆栈显然是SQL解析报错了,SQL都是生成的,按理应该也没有错,这个时候才关注到字段名可能是数据库关键字,导致解析失败,报了一个莫名其妙的NPE。

Caused by: java.lang.NullPointerException
        at org.antlr.v4.runtime.tree.AbstractParseTreeVisitor.visit(AbstractParseTreeVisitor.java:18) ~[antlr4-runtime-4.7.2.jar!/:4.7.2]
        at org.apache.shardingsphere.sql.parser.mysql.visitor.impl.MySQLDMLVisitor.visitInsert(MySQLDMLVisitor.java:147) ~[shardingsphere-sql-parser-mysql-4.1.1.jar!/:4.1.1]
        at org.apache.shardingsphere.sql.parser.mysql.visitor.impl.MySQLDMLVisitor.visitInsert(MySQLDMLVisitor.java:127) ~[shardingsphere-sql-parser-mysql-4.1.1.jar!/:4.1.1]
        at org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser$InsertContext.accept(MySQLStatementParser.java:1090) ~[shardingsphere-sql-parser-mysql-4.1.1.jar!/:4.1.1]

4. 经验教训

  1. 用shardingsphere之类的,要注意是否为关键字,否则有莫名奇妙的问题
  2. 代码错误可读性和精准,如果一开始报错就是SQL内有关键字,或者MybatisPlus生成SQL的时候转义SQL,体验会好很多
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值