Mysql數據類型TINYINT(1)與BOOLEAN踩坑記


  熟悉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代碼中進行修改,修改后的影響,還需另外評估。

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM