ShardingSphere 踩过的坑:Cannot invoke method div() on null object

背景

Java:8
ShardingSphere:4.0.0-RC1
SpringBoot:2.1.9.RELEASE
mybatis-spring-boot-starter:2.1.4 (mybatis 3.5.6)
数据源:druid 1.1.16

分表分库规则

t_user 表 DDL:

CREATE TABLE `t_user0` (
  `USER_ID` bigint(20) NOT NULL,
  `TENANT_ID` bigint(20) NOT NULL,
  PRIMARY KEY (`USER_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

分库分表思路:10 个租户一个物理库,2000w 个用户一张用户表。规则配置如下所示:

# 数据分库规则 - 指定分库主键
spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=tenant_id
# 数据分库规则 - 分库规则为主键除以 10 取整
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds$->{tenant_id / 10 as int}
# 数据分表规则
# 指定所需分流的表
spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=ds$->{0..1}.t_user$->{0..5}
# 指定主键
spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.sharding-column=user_id
# 分表规则为主键除以 1000 取整
spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.algorithm-expression=t_user$->{user_id / 1000 as int}

TabUserMapper.xml 插入一行记录相关代码如下:

    <insert id="insertSelective" parameterType="com.sharding.tabledemo.pojo.TabUser">
        insert into t_user(USER_ID, TENANT_ID) values(#{userId}, #{tenantId})
    </insert>

报错信息

测试插入逻辑的时候,ShardingSphere 报错:

2022-03-14 15:45:37.660 ERROR 6896 --- [nio-9343-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: 
### Error updating database.  Cause: java.lang.NullPointerException: Cannot invoke method div() on null object
### The error may exist in file [D:\tmp\table-demo\target\classes\mapper\TabUserMapper.xml]
### The error may involve com.sharding.tabledemo.mapper.TabUserMapper.insertSelective-Inline
### The error occurred while setting parameters
### SQL: insert into t_user(USER_ID, TENANT_ID) values(?, ?})
### Cause: java.lang.NullPointerException: Cannot invoke method div() on null object] with root cause

java.lang.NullPointerException: Cannot invoke method div() on null object
	at org.codehaus.groovy.runtime.NullObject.invokeMethod(NullObject.java:91) ~[groovy-2.4.5-indy.jar:2.4.5]

解决方案

去 ShardingSphere 维护的 github 上的 issues 列表中搜索,虽然报的不一定是 div() 方法,但大体也能给出改错方向:

于是反复检查 inline,很不幸的是没有发现语法或逻辑错误;分片键和分片策略中的字段是拷贝复制的已经没法再一致了。
最后发现,问题竟然是 inline 和 TabUserMapper.xml 里的相关字段大小写不一致导致的。
于是把 TabUserMapper.xml 上述伪代码部分分片主键相关改为和 inline 一致:

    <insert id="insertSelective" parameterType="com.sharding.tabledemo.pojo.TabUser">
        insert into t_user(user_id, tenant_id) values(#{userId}, #{tenantId})
    </insert>

问题顺利解决。

posted @ 2022-03-14 16:51  Defonds  阅读(677)  评论(0编辑  收藏  举报