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。