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

  熟悉Mysql的同窗應該都知道,Mysql查詢的boolean結果將輸出爲0或者1.html

  好比:java

select 1=1;

  其輸出結果爲1。mysql

  查閱mysql官方文檔僅找到以下描述:sql

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:app

 
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 語句,其中遇到以下的問題,ui

  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類型進行返回了。this

  總結:Mysql表結構設計時,要避免設計爲tinyint(1)這種類型,以避免與boolean類型數據結構進行混淆。引發沒必要要bug。固然也能夠總java代碼中進行修改,修改後的影響,還需另外評估。spa

相關文章
相關標籤/搜索