数据库设计中boolean类型的处理

2021-03-15 12:09 阅读

数据库的boolean值是一个令人头疼的问题,涉及到多方面的问题。

命名

数据库中的boolean字段,以什么方式命名?通常会要求boolean值以is开头,比如阿里的数据库设计规范强制要求boolean型以is_开头,比如is_deleted。这确实可以很直观的让人知道某个字段的类型,我也很喜欢这样。

但是命名不仅仅是在数据库里面,JavaBean里面如何命名呢?为了统一性(特别是使用工具从数据库生成Java类),JavaBean里的属性名应该和数据库字段名一致,当然是isDeleted

那么问题来了,JavaBean的get、set方法如何写呢?如果用开发工具(如IntelliJ IDEA)生成,会是这样:

public class User {
    private Boolean isDisabled;

    public Boolean getDisabled() {
        return isDisabled;
    }

    public void setDisabled(Boolean disabled) {
        isDisabled = disabled;
    }
}

有些生成工具产生如下代码也不要奇怪:

public class User {
    private Boolean isDisabled;

    public Boolean getIsDisabled() {
        return this.isDisabled;
    }

    public void setIsDisabled(Boolean isDisabled) {
        this.isDisabled = isDisabled;
    }
}

如果使用原生类型boolean而非对象类型Boolean,则代码如下:

public class User {
    private boolean isDisabled;

    public boolean isDisabled() {
        return this.isDisabled;
    }

    public void setDisabled(boolean disabled) {
        this.isDisabled = disabled;
    }
}

再用jackson生成JSON,会是{disabled:false}{isDisabled:false}

于是数据库isDisabled,JavagetDisabled() isDisabled() getIsDisabled(),JSONdisabled isDisabled。是不是有点凌乱?

太混乱了,所以有很多开发规范里禁止JavaBean属性使用is开头。

数据库说要is开头,JavaBean说不要is开头,到底要不要?也许可以让数据库的字段用is开头,在JavaBean里则去掉is。这是一个办法,但从数据库自动生成JavaBean的时候,就要手动改了。而且JavaBean、JSON里都没有is开头,在数据库里又突然又有is开头,也是一种混乱。

最后的结论是,都不要is开头,且boolean型不能为空。JavaBean用原生类型boolean而不是Boolean。这样数据库disabled,JavaisDisabled(),JSONdisabled,这样就简单明了多了。

另:可为空的Boolean可以考虑用char(1),如性别(m:男,f:女,n:保密)。

数据库类型

虽然boolean型是SQL标准的数据类型,但很多数据库都没有提供boolean类型,理由是这个数据类型太容易代替了,没有必要专门用一个数据类型。比如用char(1)或者int。

可代替是可代替,那实际使用中,怎么代替才是最佳实践呢?

Hibernate是这样处理的:

  • 使用数值型(如int或者tinyint),则0表示false1表示true
  • 使用字符型(如char(1)),则N/n表示false, Y/y表示true,或者F/f表示false, T/t表示true

很显然使用数值型比较直观,毕竟和c语言的规则一致,计算机一贯的传统。

字符型则稍显混乱,当然字符型也可以用0和1,特别是在oracle中用char(1)比用number(1)更节省空间。char(1)占一个字节,number(1)占两个字节。在其它没有1字节的数值型数据库中,也是这样(如DB2)。

char(1)还一个问题,就是数据库自动生成JavaBean时,无法判断是字符型还是boolean型。特别时字段不以is开头,就更无法自动判断了,这对自动生成代码很不友好。众所周知,自动生成代码在开发里面有着很高地位,没有人愿意把时间花在重复的、没有意义的事情上面。

MySQL中,有boolean类型,但这个类型是tinyint(1)的同义词,就是说boolean也是用数值存储的。

阿里的数据库设计规范也是要求使用tinyint(1)存储boolean类型。

数据库管理工具liquibase的规则是有boolean类型的直接用,没有的用bit或者数值代替:

MySQLDatabase: BIT(1)
SQLiteDatabase: BOOLEAN
H2Database: BOOLEAN
PostgresDatabase: BOOLEAN
UnsupportedDatabase: BOOLEAN
DB2Database: SMALLINT
MSSQLDatabase: [bit]
OracleDatabase: NUMBER(1)
HsqlDatabase: BOOLEAN
FirebirdDatabase: SMALLINT
DerbyDatabase: SMALLINT
InformixDatabase: BOOLEAN
SybaseDatabase: BIT
SybaseASADatabase: BIT

liquibase在MySQL中使用BIT(1),没有直接用MySQL的boolean类型,这个有点奇怪,可能liquibase认为MySQL的boolean是假的(实际是tinyint(1)),还不如用BIT(1)。咱就不和数据库较这个劲了,直接用MySQL的boolean,数据库说啥就是啥,它总比我们了解它自己吧,总不能让我们吃什么大亏。

如此看来,并不好逆流而动用char(1)作为boolean。至少看在代码自动生成的份上,开发环境上用数值做boolean(一般是MySQL,直接用bool类型,数据库自动转为tinyint(1))。生成其它数据库脚本时,如果为了方便(char(1)所有的数据库都有)或者节省存储空间,将boolean转成char(1)也许不是什么大问题(MyBatis会映射成BIT类型,不知能否操作char(1))。

参考资料

阿里MySQL数据库建表规约

咨询
交流群
电话