java查询MySQL时,MySQL中tinyint长度为1时转换为boolean

不使用实体类接收数据时,mysql查询tinyint(1) 的数据时,0会被转为false,1或以上会转为true.

在mysql与java之间的数据类型对照表中找到了答案

对照表链接:

http://www.jianshu.com/p/1f70197da6a8

关于tinyint是这样描述的

java.lang.Boolean if the configuration property tinyInt1isBit is set to true (the default) and the storage size is 1, or java.lang.Integer if not.

大概意思就是如果长度为1并且设置了tinyInt1isBit = true,就会对应Boolean.否则对应integer

这里请注意,tinyInt1isBit 默认就是true,

所以解决办法就是将数据库配置的url加上这样的参数 : 

&tinyInt1isBit=false

Java、JDBC与MySQL数据类型对照数据类型之间的转换

开头唠嗑

前几天在设计数据库时偶然发现mysql还有tinyint 型的字段,百度之后知道了

TINYINT ,字段类型,如果设置为UNSIGNED类型,只能存储从0到255的整数,不能用来储存负数
TINYINT 型的字段如果不设置UNSIGNED类型,存储-128到127的整数。

因此我发现用1个tinyint型数据只占用一个字节;一个INT型数据占用四个字节。这看起来似乎差别不大,但是在比较大的表中,字节数的增长是很快的。这个数据类型也确实能为我们节省一定存储空间。
看着不错我决定用它来存储成绩,感觉大小刚刚好,那么他在java中又对应什么类型呢?反正寒假在家除了敲代码也没有什么乐趣了拍照摄影?外面雾霾大,在家吧,索性把他们之间的关系理理。

官方的关系对应表

引自mysql.com-- Java, JDBC and MySQL Types

MySQL类型名 返回值 GetColumnClassName 返回的Java类型
BIT(1) (new in MySQL-5.0) BIT java.lang.Boolean
BIT( > 1) (new in MySQL-5.0) BIT byte[]
TINYINT TINYINT java.lang.Boolean if the configuration property tinyInt1isBit is set to true (the default) and the storage size is 1, or java.lang.Integer if not.
BOOL, BOOLEAN TINYINT See TINYINT, above as these are aliases for TINYINT(1), currently.
SMALLINT[(M)] [UNSIGNED] SMALLINT [UNSIGNED] java.lang.Integer (regardless of whether it is UNSIGNED or not)
MEDIUMINT[(M)] [UNSIGNED] MEDIUMINT [UNSIGNED] java.lang.Integer (regardless of whether it is UNSIGNED or not)
INT,INTEGER[(M)] [UNSIGNED] INTEGER [UNSIGNED] java.lang.Integer, if UNSIGNED java.lang.Long
BIGINT[(M)] [UNSIGNED] BIGINT [UNSIGNED] java.lang.Long, if UNSIGNED java.math.BigInteger
FLOAT[(M,D)] FLOAT java.lang.Float
DOUBLE[(M,B)] DOUBLE java.lang.Double
DECIMAL[(M[,D])] DECIMAL java.math.BigDecimal
DATE DATE java.sql.Date
DATETIME DATETIME java.sql.Timestamp
TIMESTAMP[(M)] TIMESTAMP java.sql.Timestamp
TIME TIME java.sql.Time
YEAR[(2/4)] YEAR If yearIsDateType configuration property is set to false, then the returned object type is java.sql.Short. If set to true (the default), then the returned object is of type java.sql.Datewith the date set to January 1st, at midnight.
CHAR(M) CHAR java.lang.String (unless the character set for the column is BINARY, then byte[] is returned.
VARCHAR(M) [BINARY] VARCHAR java.lang.String (unless the character set for the column is BINARY, then byte[] is returned.
BINARY(M) BINARY byte[]
VARBINARY(M) VARBINARY byte[]
TINYBLOB TINYBLOB byte[]
TINYTEXT VARCHAR java.lang.String
BLOB BLOB byte[]
TEXT VARCHAR java.lang.String
MEDIUMBLOB MEDIUMBLOB byte[]
MEDIUMTEXT VARCHAR java.lang.String
LONGBLOB LONGBLOB byte[]
LONGTEXT VARCHAR java.lang.String
ENUM('value1','value2',...) CHAR java.lang.String
SET('value1','value2',...) CHAR java.lang.String

跨类型转换

下图展示了MySQL JDBC允许的跨类型相互转换。

这些mysql数据类型 总是可以转换为这些java类型
CHAR, VARCHAR, BLOB, TEXT, ENUM, and SET java.lang.String, java.io.InputStream, java.io.Reader, java.sql.Blob, java.sql.Clob
FLOAT, REAL, DOUBLE PRECISION, NUMERIC, DECIMAL, TINYINT, SMALLINT, MEDIUMINT, INTEGER, BIGINT java.lang.String, java.lang.Short, java.lang.Integer, java.lang.Long, java.lang.Double, java.math.BigDecimal
DATE, TIME, DATETIME, TIMESTAMP java.lang.String, java.sql.Date, java.sql.Timestamp

注意

如果选择的Java数值数据类型的精度或容量低于要转换/来自的MySQL数据类型,则可能会出现舍入,溢出或精度丢失。

MySQL Connector / J在处理MySQL数据类型和Java数据类型之间的转换方式方面是灵活的。

在一般情况下,任何MySQL数据类型可以转换为一个 java.lang.String,任何数值类型可以转换为任意的Java数字类型的,虽然可能会出现舍入,溢出或精度损失。

参考建议

Java, JDBC and MySQL Types
Mybatis源代码分析之类型转换

MySQL JDBC 中 tinyint(1) 处理为Boolean 的代码逻辑_mysql tinyint boolean-CSDN博客

MySQL JDBC 中 tinyint(1) 类型,在查询时默认会被处理为 Boolean 类型。

参数配置

官方文档中提供了参数配置
在这里插入图片描述

上图标记的两个参数可以控制如何处理 tinyint(1) 类型和 BIT 类型。

tinyInt1isBit 默认 true,因此会把 tinyint(1) 类型转换为 BIT 类型。

转换的逻辑在 com.mysql.jdbc.Field 类中的构造方法,相关的部分代码如下:

if (this.sqlType == Types.TINYINT && this.length == 1 
    && this.connection.getTinyInt1isBit()) {
    // Adjust for pseudo-boolean
    if (conn.getTinyInt1isBit()) {
        if (conn.getTransformedBitIsBoolean()) {
            this.sqlType = Types.BOOLEAN;
        } else {
            this.sqlType = Types.BIT;
        }
    }
}

这里可以看到最后的 sqlType 属性会变成 Types.BIT 类型。

取值时为什么会变成 Boolean 类型呢?

类型对应关系

先看官方文档中SQL类型和Java类型的对应关系
在这里插入图片描述
这里可以看到 BIT 类型转换为了 Boolean 类型。这个转换规则和取值调用的具体方法有关。

通过 ResultSet.getInt(int columnIndex) 方法调用时,tinyint(1) 可以返回正常的 0~9 的值,通过 ResultSet.getBoolean(int columnIndex) 时,会按照一定的规则转换为 Boolean 类型。

只有当通过调用 ResultSet.getObject(int columnIndex) 方法时,才会按照前面 Field 中的 sqlType 类型去调用对应的 getXX类型(int columnIndex) 方法,在 com.mysql.jdbc.ResultSetImpl 中的 getObject 方法的部分代码如下:

switch (field.getSQLType()) {
   case Types.BIT:
        if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_BIT && !field.isSingleBit()) {
            return getObjectDeserializingIfNeeded(columnIndex);
        }
        return Boolean.valueOf(getBoolean(columnIndex));

    case Types.BOOLEAN:
        return Boolean.valueOf(getBoolean(columnIndex));

这里会通过 getBoolean(columnIndex) 取值,结果是 Boolean 类型。

MySQL 参数中的 transformedBitIsBoolean 只是觉得是否直接把 sqlType 从 BIT 转换为 Boolean 类型,不管是否转换,在 Java 中都是 Boolean 类型。

如果不想让 tinyint(1) 类型处理为 Boolean 类型,设置 tinyInt1isBit=false参数即可。

测试代码

下面是可以用来测试的代码,创建数据库,添加下面的测试表:

CREATE TABLE `test_bit` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `test` tinyint(1) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

INSERT INTO `test_bit`(`test`) VALUES (0), (1), (2);

纯JDBC测试代码(注意添加mysql驱动):

boolean类型

MYSQL保存BOOLEAN值时用1代表TRUE,0代表FALSE,boolean在MySQL里的类型为tinyint(1),

MySQL里有四个常量:true,false,TRUE,FALSE,它们分别代表1,0,1,0,

mysql> select true,false,TRUE,FALSE;

+——+——-+——+——-+

| TRUE | FALSE | TRUE | FALSE |

+——+——-+——+——-+

|    1 |     0 |    1 |     0 |

+——+——-+——+——-+

可以如下插入boolean值:insert into [xxxx(xx)] values(true),当然也可以values(1);

举例如下:

mysql> alter table test add isOk boolean;

Query OK

mysql> desc test;

+——-+————-+——+—–+———+—————-+

| Field | Type        | Null | Key | Default | Extra          |

+——-+————-+——+—–+———+—————-+

| id    | int(11)     | NO   | PRI | NULL    | auto_increment |

| isOk  | tinyint(1)  | YES  |     | NULL    |                |

+——-+————-+——+—–+———+—————-+

mysql> insert into test(isOk) values(true);

Query OK

mysql> select isOk from test ;

+——+

| isOk |

+——+

|    1 |

+——+

=================

MySQL没有boolean类型。这也是比较奇怪的现象。例:

create table xs

(

id int primary key,

bl boolean

)

这样是可以创建成功,但查看一下建表后的语句,就会发现,mysql把它替换成tinyint(1)。也就是说mysql把boolean=tinyInt了,但POJO类要定义成什么类型呢?

因为惯性思维,在java类中也把它定义成type。然后在Struts中使用标签。这就产生一个严重的问题了。是boolean,而POJO去定义成byte。这样数据永远也无法提交,被struts的intercept拦截掉了。解决办法是在POJO类中定义成boolean,在mysql中定义成tinyint(1)。   ——  TINYINT(1) or ENUM( ‘true’ , ‘false’) ——-,

boolean类型

MYSQL保存BOOLEAN值时用1代表TRUE,0代表FALSE,boolean在MySQL里的类型为tinyint(1),

MySQL里有四个常量:true,false,TRUE,FALSE,它们分别代表1,0,1,0,

mysql> select true,false,TRUE,FALSE;

+——+——-+——+——-+

| TRUE | FALSE | TRUE | FALSE |

+——+——-+——+——-+

|    1 |     0 |    1 |     0 |

+——+——-+——+——-+

可以如下插入boolean值:insert into [xxxx(xx)] values(true),当然也可以values(1);

举例如下:

mysql> alter table test add isOk boolean;

Query OK

mysql> desc test;

+——-+————-+——+—–+———+—————-+

| Field | Type        | Null | Key | Default | Extra          |

+——-+————-+——+—–+———+—————-+

| id    | int(11)     | NO   | PRI | NULL    | auto_increment |

| isOk  | tinyint(1)  | YES  |     | NULL    |                |

+——-+————-+——+—–+———+—————-+

mysql> insert into test(isOk) values(true);

Query OK

mysql> select isOk from test ;

+——+

| isOk |

+——+

|    1 |

+——+

=================

MySQL没有boolean类型。这也是比较奇怪的现象。例:

create table xs

(

id int primary key,

bl boolean

)

这样是可以创建成功,但查看一下建表后的语句,就会发现,mysql把它替换成tinyint(1)。也就是说mysql把boolean=tinyInt了,但POJO类要定义成什么类型呢?

因为惯性思维,在java类中也把它定义成type。然后在Struts中使用标签。这就产生一个严重的问题了。是boolean,而POJO去定义成byte。这样数据永远也无法提交,被struts的intercept拦截掉了。解决办法是在POJO类中定义成boolean,在mysql中定义成tinyint(1)。   ——  TINYINT(1) or ENUM( ‘true’ , ‘false’) ——-

 

理解误区——mysql中tinyint与Java的数据类型的对应关系;tinyint(1) 与tinyint(4)的区别_tinyint用什么类型接收-CSDN博客

理解误区1

   在最初学习Java和MySQL的时,一直使用的是Boolean来接受tinyint类型的数据。具体操作:在数据库中设置TINYINT(1),存储0和1;在Java中使用boolean来接受,0代表false,1代表true。在潜意识中一直以为MySQL的tinyint对应Java的Boolean,其实这个是错误的。
   直到后来使用tinyint存不是0和1的数之后,才考虑到Java应该用什么类型接收,才明白之前的那个“潜意识”是错误的。

tinyint用java的什么类型来接收?

tinyint 可以使用int来接受也可以用boolean来接受。

因为数据库并没有boolean这个类型,所以可以使用tinyint来代替,0代表false,1代表true。

理解误区2

   之前总是使用TINYINT(1)来存储0和1的数据,“(1)”虽是显示长度,但是总感觉可以节省空间。其实这是错误的,是和varchar弄混淆了

tinyint(1) 与tinyint(4)的区别?

tinyint默认的位数是4位,但是我们设计数据库就算设计成tinyint(1),也不能影响它占了4个存储空间。

tinyint(1) 和 tinyint(4)中的1和4只有字段指定zerofill是有用,用0来填充,而且需要去指定zerofill才行。

其实他们的存储空间是一样的。
如tinyint(4),如果实际值是2,如果列指定了zerofill,查询结果就是0002,左边用0来填充。

 

Mybatis Generator 对于Tinyint映射为Byte和Boolean

1. 对于tinyint(4)映射为Byte

1.1 环境
  • spring boot 2.1.x
  • mybatis
  • tk.mybatis
  • mysql
1.2 自定义类型解析器

(1) 新建以下类

public class CustomerJavaTypeResolver extends JavaTypeResolverDefaultImpl {

    public CustomerJavaTypeResolver() {
        super();
        //把数据库的 TINYINT 映射成 Integer
        super.typeMap.put(Types.TINYINT, new JavaTypeResolverDefaultImpl.JdbcTypeInformation("TINYINT", new FullyQualifiedJavaType(Integer.class.getName())));
    }
}

(2)在pom.xml中加入

<build>
        <plugins>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.6</version>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>5.1.29</version>
                    </dependency>
                    <!--<dependency>
                        <groupId>org.mybatis.generator</groupId>
                        <artifactId>mybatis-generator-core</artifactId>
                        <version>1.3.6</version>
                    </dependency>-->
                    <dependency>
                        <groupId>com.taco.cloud</groupId>
                        <artifactId>-generator-core</artifactId>
                        <version>1.0-SNAPSHOT</version>
                    </dependency>
                    <dependency>
                        <groupId>tk.mybatis</groupId>
                        <artifactId>mapper</artifactId>
                        <version>4.1.5</version>
                    </dependency>
                </dependencies>
                <!--<executions>
                    <execution>
                        <id>Generate MyBatis Artifacts</id>
                        <phase>package</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>-->
                <configuration>
                    <!--允许移动生成的文件 -->
                    <verbose>true</verbose>
                    <!-- 是否覆盖 -->
                    <overwrite>true</overwrite>
                    <!-- 自动生成的配置 -->
                    <configurationFile>
                        src/main/resources/mybatis-generator.xml</configurationFile>
                </configuration>
            </plugin>
        </plugins>
    </build>

(3)修改mybatis-generator.xml文件,加入

<javaTypeResolver type="com.taco.springcloud.generator.CustomerJavaTypeResolver">
            <!--
            true:使用BigDecimal对应DECIMAL和 NUMERIC数据类型
            false:默认,
               scale>0;length>18:使用BigDecimal;
               scale=0;length[10,18]:使用Long;
               scale=0;length[5,9]:使用Integer;
               scale=0;length<5:使用Short;
             -->
            <property name="forceBigDecimals" value="false"/>

        </javaTypeResolver>

2. 对于tinyint(1)映射为Boolean情况

2.1 解决方法
  1. JDBC的URL增加 tinyInt1isBit=false参数,注意参数名区分大小写,否则不生效

    例如:jdbc:mysql://${ucmha.proxy1_2.host}/${db.mysql.db}?tinyInt1isBit=false

  2. 用tinyint(2)代替

posted @ 2024-03-26 10:15  CharyGao  阅读(716)  评论(0)    收藏  举报