bigint 有无符号对应java的Long和BigInteger
这个问题是在实际工作中遇到的,是一个小的问题,但是如果不注意的话,造成的后续问题是比较严重的。下面就来重现一下这个问题。
首先我们先创建一张数据表,名为t_order
. 位于test
库中。
CREATE TABLE `t_order` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`tid` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
SQL语句如上,字段tid上是正常的bigint
类型,无其他限制条件。
下面使用SpringBoot+Mybatis
来测试数据查询单独tid列。
通过Debug可以看到allTids
的数据是Long
类型的。下面我们将数据库表修改一下。
CREATE TABLE `t_order` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`tid` bigint(20) unsigned DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
此时表的SQL如上,即在tid列上加上了无符号限制。我们重新运行测试代码:
测试结果如上,可以看出,测试的tid
类型就变成了BigInteger
类型。当然在我们的控制台直接输出是不会出现问题的,但是将测试代码换成下面的:
通过测试结果可以看出,无法将相应的Long类型的数据剔除掉。
当然,这个问题如果在Mybatis中使用泛型限制的话,也不会出现自动映射为BigInteger的情况。
public interface OrderMapper {
List findAllTids();
List<Long> findAllLongTids();
List<Map<String,Object>> findAll();
}
通过上面的截图可以看出,由于查询的时候使用了泛型进行相应的类型限制,可以看出即使在数据库表中设置了tid的类型为无符号,也可以自动转为Long类型。这种情况下是不会出现问题的。
但是公司的DAO层比较多样化,有一部分DAO层
是基于apache的DBUtils
进行封装的,对于切换数据源比较方便,所以使用时偏向于这个,但是在查询单列的id时,遇到了上述情况,加了泛型也是无法转换,我进入源码并且看到这样一段代码:
public abstract class AbstractListHandler<T> implements ResultSetHandler<List<T>> {
public AbstractListHandler() {}
public List<T> handle(ResultSet rs) throws SQLException {
ArrayList rows = new ArrayList();
while(rs.next()) {
rows.add(this.handleRow(rs));
}
return rows;
}
protected abstract T handleRow(ResultSet var1) throws SQLException;
}
// 单列的数据处理
public class ColumnListHandler<T> extends AbstractListHandler<T> {}
可以看出,在DBUtils
的AbstractListHandler
类中,在处理时,并没有进行类型限制,只是在方法声明的地方添加了T
,其实没什么用,查询出来该是BigInteger还是这个,不会自动转为泛型设置的类型。(这里是个坑),但是使用Mybatis可以避免了。
说明:如果是有符号的 Bigint(20) 取值范围是-9223372036854775808~9223372036854775807
,与 Java中的java.lang.Long的取值范围是一致的,而如果是无符号的Bigint(20),其取值范围是0 ~ 18446744073709551615
,其中一般超出了Long的取值范围,会被映射为BigInteger。