ShardingSphere报Sharding value must implements Comparable.的解决过程

一、在使用sharding sphere操作垂直分表数据库demo的时候,执行插入操作一直报这个莫名奇妙的错误,翻译大致的意思是:分片值必须实现Comparable。首先通过翻译猜测应该是有两种可能:①是指实体类需要实现Comparable接口,然后就跑去官网重新看了一边快速开始,但是并没有这样的要求。②可能少配置了什么,然后对着官网的配置又捋了一边,没有配置错误,但是阴差阳错,我发现如果主键值自己写进去就可以插入成功,先说下我的代码结构
二、代码结构
因为是一个demo所以比较简单,首先数据库有两个表,user_1和user_2,
采用springboot+mybatis+sharding-idbc数据库使用的是mysql
实体类:

import lombok.Data;
import org.apache.ibatis.type.Alias;

@Alias("User")
@Data
public class User {
    private Long uid;
    private String uName;
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.joe.shardingdemo.mapper.UserMapper">
    <insert id="insertUser" parameterType="User" keyColumn="uid" keyProperty="uid">
        INSERT INTO test(`uid`,`u_name`)
        VALUES
        (#{uid},#{uName,jdbcType=VARCHAR})
    </insert>
</mapper>

application.properties文件


# Mybatis配置
# xml文件位置
mybatis.mapper-locations=classpath:mapper/*.xml
# 实体类所在包
mybatis.type-aliases-package=com.joe.shardingdemo.pojo
# 驼峰命名配置
mybatis.configuration.map-underscore-to-camel-case=true


# sharding-sphere配置
# 数据库配置,分库用逗号隔开
spring.shardingsphere.datasource.names=ds1

# 数据源配置
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://localhost:3306/test_cas
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=root

# 分表名称配置,其中的user为表名,test_cas.user_$->{1..2}表示数据库test_cas下两个表user_1和user_2
spring.shardingsphere.sharding.tables.test.actual-data-nodes=ds1.test_$->{1..2}
# 配置分表策略,其中的user为表名,u_id为策略判断的列的名称,
spring.shardingsphere.sharding.tables.test.table-strategy.inline.sharding-column=uid
# user_$->{u_id % 2 + 1}  表示操作的表为 user_ + "uid对2取模+1确定操作哪张表"
spring.shardingsphere.sharding.tables.test.table-strategy.inline.algorithm-expression=test_$->{uid % 2 + 1}
# 标明主键 user表的主键为u_id
spring.shardingsphere.sharding.tables.test.key-generator.column=uid
# 标明主键通过雪花算法自动生成
spring.shardingsphere.sharding.tables.test.key-generator.type=SNOWFLAKE


# 开启打印sql语句
spring.shardingsphere.props.sql.show=true

测试类

@SpringBootTest
class ShardingDemoApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    void contextLoads() {
        for(int i=0;i<10;i++){
            User user = new User();
            // 如果手动添加主键是可以添加的
            user.setUid(1l);
            user.setUName("test");
            userMapper.insertUser(user);
        }
    }

}

三、在测试的时候发现手动添加主键的值是可以插入的,所以问题大致定位在主键的生成上,因为是分布式的,所以shardingSphere为我们内置了推特的雪花算法,我在主键配置那里也是指定了SNOWFLAKE
在这里插入图片描述ShardingSphere报Sharding value must implements Comparable.的解决过程_第1张图片
所以首先,看主键是否有生成,shardingsphere雪花算法相关的类是SnowflakeShardingKeyGenerator.generateKey(),所以在这个方法上打断点,发现并没有执行这个方法,所以感觉问题又进一步缩小了,应该是主键没有自动生成导致的。查看网上资料,sharding在插入的时候,会调用ShardingInsertOptimizeEngine.optimize()来执行插入操作
ShardingSphere报Sharding value must implements Comparable.的解决过程_第2张图片
在这里看到有对应的生成主键的方法,打端点,报错的具体位置就是这里。
ShardingSphere报Sharding value must implements Comparable.的解决过程_第3张图片
打断点进这个方法,这个方法先获取需要自动生成主键的列名,仔细看return那里的三目运算符,会做一个判断,如果要生成的列名包含在insertColumns(列名数组)里面,就会调用findGeneratedKey去找主键的值,反之,才会调用createGeneratedKey方法生成主键,createGeneratedKey会调用刚才说的SnowflakeShardingKeyGenerator.generateKey()用雪花算法生成主键。所以正确的是让程序去调用createGeneratedKey生成而不是去查找,因为本来就没有主键值,所以会报错,具体可以在往深了打断点,本质就是调用原生JDBC的ParperStatment去放值的时候放了一个null,报错的。
所以关键就是要去看这个insertColumns是怎么生成的,往上一层找调用这个方法的方法,发现是通过我们在mapper中配置的sql语句解析出的这个insertColumns,所以在这里我们只需要修改mapper文件,将主键去掉就可以了。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.joe.shardingdemo.mapper.UserMapper">
    <insert id="insertUser" parameterType="User" keyColumn="uid" keyProperty="uid">
        INSERT INTO test(/*`uid`,*/`u_name`)
        VALUES
        (/*#{uid},*/#{uName,jdbcType=VARCHAR})
    </insert>
</mapper>

写sql的时候不用写主键列,sharding sphere会帮我们自动生成的,并动态插入,好了,问题解决。
ShardingSphere报Sharding value must implements Comparable.的解决过程_第4张图片

你可能感兴趣的:(微服务,sharding,sphere)