熟悉Mysql的同学应该都知道,Mysql查询的boolean结果将输出为0或者1.

  比如:

select 1=1;

  其输出结果为1。

  查阅mysql官方文档仅找到如下描述:

11.10 Using Data Types from Other Database Engines

To facilitate the use of code written for SQL implementations from other vendors, MySQL maps data types as shown in the following table. These mappings make it easier to import table definitions from other database systems into MySQL.

Other Vendor Type MySQL Type
BOOL TINYINT
BOOLEAN TINYINT
CHARACTER VARYING(M) VARCHAR(M)
FIXED DECIMAL
FLOAT4 FLOAT
FLOAT8 DOUBLE
INT1 TINYINT
INT2 SMALLINT
INT3 MEDIUMINT
INT4 INT
INT8 BIGINT
LONG VARBINARY MEDIUMBLOB
LONG VARCHAR MEDIUMTEXT
LONG MEDIUMTEXT
MIDDLEINT MEDIUMINT
NUMERIC DECIMAL
Other Vendor Type MySQL Type

Data type mapping occurs at table creation time, after which the original type specifications are discarded. If you create a table with types used by other vendors and then issue a DESCRIBE tbl_name statement, MySQL reports the table structure using the equivalent MySQL types. For example:

 
mysql> CREATE TABLE t (a BOOL, b FLOAT8, c LONG VARCHAR, d NUMERIC);
Query OK, 0 rows affected (0.00 sec) mysql> DESCRIBE t;
+-------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| a | tinyint(1) | YES | | NULL | |
| b | double | YES | | NULL | |
| c | mediumtext | YES | | NULL | |
| d | decimal(10,0) | YES | | NULL | |
+-------+---------------+------+-----+---------+-------+
4 rows in set (0.01 sec)

  我想说的是,今天使用一套中间件对kafka消息进行解析为mysql 语句,其中遇到如下的问题,

  1. 目标表有一字段设置类型为:tinyint(1)。
  2. 源表同步消息中接收到相同类型的数据。
  3. 其中中间件中有如下解析部分:
    public void setStatement(PreparedStatement statement, DatabaseType databaseType, boolean timestampChangeToLong) throws SQLException {
    if (this.value == null) {
    statement.setNull(this.index, this.sqlType);
    } else {
    switch(this.sqlType) {
    case -15:
    case -9:
    case 1:
    case 12:
    case 2005:
    String strVal = String.valueOf(this.value);
    statement.setString(this.index, strVal);
    break;
    case -7:
    case 16:
    boolean booleanVal = (Boolean)this.value; //tinyint(1) 类型的表设计字段直接进入该case,由于接收到的消息中的数据为0或者1,直接在该位置报类转换异常。
    statement.setBoolean(this.index, booleanVal);
    break;
    case -6:
    int val2 = (Integer)this.value;
    statement.setInt(this.index, val2);
    break;
    case -5:
    long longVal = (Long)this.value;
    statement.setLong(this.index, longVal);
    break;
    case 2:
    this.setStatementDataTypeNumeric(statement);
    break;
    case 3:
    this.setStatementDataTypeDecimal(statement, databaseType, timestampChangeToLong);
    break;
    case 4:
    int val = (Integer)this.value;
    statement.setInt(this.index, val);
    break;
    case 5:
    int val1 = (Integer)this.value;
    statement.setInt(this.index, val1);
    break;
    case 6:
    float floatVal = (Float)this.value;
    statement.setFloat(this.index, floatVal);
    break;
    case 8:
    double doubelVal = (Double)this.value;
    statement.setDouble(this.index, doubelVal);
    break;
    case 91:
    this.setStatementDataTypeDate(statement, databaseType);
    break;
    case 92:
    Date timeVal = (Date)this.value;
    Time sqlTime = new Time(timeVal.getTime());
    statement.setTime(this.index, sqlTime);
    break;
    case 93:
    this.setStatementDataTypeTimestamp(statement, timestampChangeToLong);
    break;
    default:
    throw new ConsumeException("sqlType " + this.sqlType + " is not support");
    } }
    }
  4. 怎样获取的数字类型呢,代码如下:
    protected Database loadInternal(String database) {
    Connection connection = null; Database var28;
    try {
    connection = this.dataSource.getConnection();//获取连接
    DatabaseMetaData metaData = connection.getMetaData();//获取元数据
    String catalog = null;
    String[] tableTypes = new String[]{"TABLE"};
    String databasePattern = this.databaseSchema != null ? this.databaseSchema : database;
    ResultSet tablesResultSet = metaData.getTables((String)catalog, databasePattern, "%", tableTypes);
    Database db = new Database();
    db.setName(database); Table tablei;
    while(tablesResultSet.next()) {
    String tableName = tablesResultSet.getString("TABLE_NAME");
    tablei = new Table(tableName);
    db.addTable(tablei);
    } Iterator var27 = db.getTables().iterator(); while(var27.hasNext()) {
    tablei = (Table)var27.next();
    ResultSet columnsResultSet = metaData.getColumns((String)catalog, databasePattern, tablei.getName(), (String)null); while(columnsResultSet.next()) {
    String columnName = columnsResultSet.getString("COLUMN_NAME");
    int sqlType = columnsResultSet.getInt("DATA_TYPE");//此处拿到mysql返回的字段类型
    String typeName = columnsResultSet.getString("TYPE_NAME");
    int size = columnsResultSet.getInt("COLUMN_SIZE");
    boolean nullable = 1 == columnsResultSet.getInt("NULLABLE");
    Column column = new Column();
    column.setName(columnName);
    column.setNullable(nullable);
    column.setSqlType(sqlType);
    column.setTypeName(typeName);
    column.setSize(size);
    tablei.addColumn(column);
    }
    } var28 = db;
    } catch (Exception var25) {
    throw new RuntimeException("load schema exception", var25);
    } finally {
    if (connection != null) {
    try {
    connection.close();
    } catch (SQLException var24) {
    ;
    }
    } } return var28;
    }
  5. 也就是说,获取字段类型时,字段tinyint(1)的类型被当做boolean类型进行了返回。导致java中Integer类型无法进行强转。

  解决方法:alter talbe change `xxx` `xxx` tinyint(4) ...;即可。修改tinyint数据类型长度,mysql也就不再当做boolean类型进行返回了。

  总结:Mysql表结构设计时,要避免设计为tinyint(1)这种类型,以免与boolean类型数据结构进行混淆。引起不必要bug。当然也可以总java代码中进行修改,修改后的影响,还需另外评估。

  

Mysql数据类型TINYINT(1)与BOOLEAN踩坑记的更多相关文章

  1. Spark踩坑记——数据库(Hbase+Mysql)

    [TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...

  2. [转]Spark 踩坑记:数据库(Hbase+Mysql)

    https://cloud.tencent.com/developer/article/1004820 Spark 踩坑记:数据库(Hbase+Mysql) 前言 在使用Spark Streaming ...

  3. Spark踩坑记——数据库(Hbase+Mysql)转

    转自:http://www.cnblogs.com/xlturing/p/spark.html 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库 ...

  4. Spark踩坑记——共享变量

    [TOC] 前言 Spark踩坑记--初试 Spark踩坑记--数据库(Hbase+Mysql) Spark踩坑记--Spark Streaming+kafka应用及调优 在前面总结的几篇spark踩 ...

  5. Spark踩坑记——从RDD看集群调度

    [TOC] 前言 在Spark的使用中,性能的调优配置过程中,查阅了很多资料,之前自己总结过两篇小博文Spark踩坑记--初试和Spark踩坑记--数据库(Hbase+Mysql),第一篇概况的归纳了 ...

  6. Spark踩坑记——Spark Streaming+Kafka

    [TOC] 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark strea ...

  7. Spark踩坑记:Spark Streaming+kafka应用及调优

    前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark streaming从k ...

  8. Vue + TypeScript + Element 搭建简洁时尚的博客网站及踩坑记

    前言 本文讲解如何在 Vue 项目中使用 TypeScript 来搭建并开发项目,并在此过程中踩过的坑 . TypeScript 具有类型系统,且是 JavaScript 的超集,TypeScript ...

  9. WinUI 3 踩坑记:第一个窗口

    本文是 WinUI 3 踩坑记 的一部分,该系列发布于 GitHub@Scighost/WinUI3Keng,文中的代码也在此仓库中,若内容出现冲突以 GitHub 上的为准. WinUI 3 应用的 ...

随机推荐

  1. zoj 3261 Connections in Galaxy War(并查集逆向加边)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3261 题意:有很多颗星球,各自有武力值,星球间有一些联系通道,现 ...

  2. 中南林业科技大学第十一届程序设计大赛 有趣的二进制 牛客网 java大数的一些方法

    链接:https://www.nowcoder.com/acm/contest/124/C来源:牛客网 题目描述 小新在学C语言的时候,邝老师告诉他double类型的数据在表示小数的时候,小数点后的有 ...

  3. Python中字典,集合和元组函数总结

    ## 字典的所有方法- 内置方法 - 1 cmp(dict1, dict2) 比较两个字典元素. - 2 len(dict) 计算字典元素个数,即键的总数. - 3 str(dict) 输出字典可打印 ...

  4. 集成学习方法Boosting和Bagging

    集成学习是通过构架并结合多个学习器来处理学习任务的一种思想, 目前主要分为两大类:Boosting和Bagging. 对于任意一种集成方法, 我们都希望学习出来的基分类器具有较高的准确性和多样性, 基 ...

  5. GC判断哪些内存需要回收

    GC的问题,主要分为:1.哪些内存需要回收?2.什么时候回收?3.如何回收?这里主要讲第一个问题. 1.哪些内存需要回收? 垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”, ...

  6. Unity3D_05_理解Unity的新GUI系统(UGUI)

    理解Unity的新GUI系统(UGUI) Unity GUI 链接:UnityEngine.UI系统基础类架构图  Unity GUI 链接:UnityEngine Event & Event ...

  7. Net基础篇_学习笔记_第十天_方法_方法的练习

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  8. 解决在Filter中读取Request中的流后,后续controller或restful接口中无法获取流的问题

    首先我们来描述一下在开发中遇到的问题,场景如下: 比如我们要拦截所有请求,获取请求中的某个参数,进行相应的逻辑处理:比如我要获取所有请求中的公共参数 token,clientVersion等等:这个时 ...

  9. Linux 笔记 - 第九章 Linux 中软件的安装

    博客地址:http://www.moonxy.com 一.前言 在 Linux 系统中,应用程序的软件包主要分为两种:1)第一种是二进制的可执行软件包,也就是解开包后就可以直接运行.在 Windows ...

  10. [Linux] telnet 具体到某个端口Connection refused

    可以参考这个链接:https://q.cnblogs.com/q/106337/