解决tinyint映射成boolean/byte的问题


前言

最近受疫情的影响,公司要做一个类似一码通的系统为客户服务。由我来进行表的设计。创建表之后需要逆向生成Java的entity、mapper、mapper.xml。由于我在数据库中定义了大量 tinyint(1) 的字段。在逆向的时候,默认生成的是Boolean类型的变量。而我们习惯于使用 Integer 作为tinyint的Java类型,这要怎么转换呢?因此这里就有两个问题需要解决:

  1. tinyint(1) 转换成数字类型而不是布尔类型
  2. tinyint(n) n>1 转换成 Integer 而非 Byte

tinyint(1) 转换成数字类型

在数据库连接url后面加上参数(建议复制,大小写错了不生效。多个keyvalue之间用 & 连接):

tinyInt1isBit=false

这一点在官方文档有说明:

翻译过来就是:当字符类型为tinyint且长度为 1 时,会被转换成布尔类型。而虽然文档上说tinyInt1isBit取false时,转Integer。实际上转过来还是 Byte

tinyint(n) n>1 转换成 Integer

MyBatis Generator 是通过JavaTypeResolver 来实现关系映射的,官方文档解释

在配置文件中有一个 标签可以用来配置映射关系。而该标签有一个 type 属性。红色字体翻译过来就是:用户可以提供一个自定义的实现,该类必须实现JavaTypeResolver接口,且必须有一个共有的默认构造器,或者沿用默认值DEFAULT,将使用JavaTypeResolverDefaultImpl来进行映射,首先我们看一看它默认的实现类的构造方法

public JavaTypeResolverDefaultImpl() {
    super();
    properties = new Properties();
    typeMap = new HashMap<>();

    // 此处省略其他字段的映射......
    typeMap.put(Types.TINYINT, new JdbcTypeInformation("TINYINT", //$NON-NLS-1$
                                                       new FullyQualifiedJavaType(Byte.class.getName())));

}

很明显,字段与Java的映射关系在构造方法中配置。我们改起来很简单,新建类继承 JavaTypeResolverDefaultImpl ,在子类构造方法中重新对 typeMap 赋值,利用 HashMap<> key相同value替换的性质替换默认的实现方式

package other;

import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl;

import java.sql.Types;

public class MyTypeResolver extends JavaTypeResolverDefaultImpl {

    public MyTypeResolver() {
        super();
        typeMap.put(Types.TINYINT, new JavaTypeResolverDefaultImpl.JdbcTypeInformation("TINYINT", //$NON-NLS-1$
                new FullyQualifiedJavaType(Integer.class.getName())));
    }
}

做完这些,将该类路径写在 type 中运行,你会发现该类无法被加载......

打包类文件,被generator所依赖

因为我所使用的generator是以Maven插件的形式集成到项目中的,插件启动的时候并不会加载我项目中的类文件。故会报类无法加载的错误。解决方法就是将该类文件打包,然后添加到插件的依赖中。如果你所在的公司项目中有公共的工具类项目可以直接在项目中写,上传到私服。如果没有,按照以下的步骤进行:

  1. 创建新项目,配好本地仓库地址
  2. 添加和你generator插件版本一样的generator依赖
  3. 新建类
  4. install

这时你的工具类就已经发布到本地仓库了。此时在原来的插件中依赖该项目,并且排除generator的依赖。就可以正常生成Integer了:


        org.mybatis.generator
        mybatis-generator-maven-plugin
        
            
                mysql
                mysql-connector-java
                5.1.27
            
            
                org.mybatis.generator
                mybatis-generator-core
                1.4.0
            
            
                com.woke
                common
                1.0-SNAPSHOT
                
                    
                        org.mybatis.generator
                        mybatis-generator-core
                    
                
            
        
        
            
                Generate MyBatis Artifacts
                package
                
                    generate
                
            
        
        
            
            true
            
            false
            
            
                src/main/resources/mybatis-generator.xml
        

generator配置

mybatis-generator.xml

<?xml version="1.0" encoding="UTF-8"?>


    
    
    
        
            
            
        
        
        
        
        

        
            
        

        
        
            
            
            
            
        
        
        
            
            
        
        
        
            
            
        
        
        

其他逆向工程的工具

通过IDEA连接数据库后,可以使用右键直接生成,高度定制化

mybaits plus 设置起来和 generator 差不多,不过方便的是可以在main方法直接设置:

// 重写Mysql关于字段类型的转换配置
dsc.setTypeConvert((globalConfig, fieldType) -> {
    String t = fieldType.toLowerCase();
    if (t.contains("char")) {
        return DbColumnType.STRING;
    } else if (t.contains("bigint")) {
        return DbColumnType.LONG;
    } else if (t.contains("tinyint(1)")) {
        return DbColumnType.INTEGER;
    } else if (t.contains("int")) {
        return DbColumnType.INTEGER;
    } else if (t.contains("text")) {
        return DbColumnType.STRING;
    } else if (t.contains("bit")) {
        return DbColumnType.BOOLEAN;
    } else if (t.contains("decimal")) {
        return DbColumnType.BIG_DECIMAL;
    } else if (t.contains("clob")) {
        return DbColumnType.CLOB;
    } else if (t.contains("blob")) {
        return DbColumnType.BLOB;
    } else if (t.contains("binary")) {
        return DbColumnType.BYTE_ARRAY;
    } else if (t.contains("float")) {
        return DbColumnType.FLOAT;
    } else if (t.contains("double")) {
        return DbColumnType.DOUBLE;
    } else if (t.contains("json") || t.contains("enum")) {
        return DbColumnType.STRING;
    } else if (t.contains("date") || t.contains("time") || t.contains("year")) {
        switch (globalConfig.getDateType()) {
            case ONLY_DATE:
                return DbColumnType.DATE;
            case SQL_PACK:
                switch (t) {
                    case "date":
                        return DbColumnType.DATE_SQL;
                    case "time":
                        return DbColumnType.TIME;
                    case "year":
                        return DbColumnType.DATE_SQL;
                    default:
                        return DbColumnType.TIMESTAMP;
                }
            case TIME_PACK:
                switch (t) {
                    case "date":
                        return DbColumnType.LOCAL_DATE;
                    case "time":
                        return DbColumnType.LOCAL_TIME;
                    case "year":
                        return DbColumnType.YEAR;
                    default:
                        return DbColumnType.LOCAL_DATE_TIME;
                }
        }
    }
    return DbColumnType.STRING;
});
mpg.setDataSource(dsc);