解決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

這一點在官方文檔有說明:

image-20200325094736352

翻譯過來就是:當字符類型為tinyint且長度為 1 時,會被轉換成布爾類型。而雖然文檔上說tinyInt1isBit取false時,轉Integer。實際上轉過來還是 Byte

tinyint(n) n>1 轉換成 Integer

MyBatis Generator 是通過JavaTypeResolver 來實現關系映射的,官方文檔解釋

image-20200325101610753

在配置文件中有一個 <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了:

<plugin>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-maven-plugin</artifactId>
        <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.27</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-core</artifactId>
                <version>1.4.0</version>
            </dependency>
            <dependency>
                <groupId>com.woke</groupId>
                <artifactId>common</artifactId>
                <version>1.0-SNAPSHOT</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.mybatis.generator</groupId>
                        <artifactId>mybatis-generator-core</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
        <executions>
            <execution>
                <id>Generate MyBatis Artifacts</id>
                <phase>package</phase>
                <goals>
                    <goal>generate</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <!-- 允許移動生成的文件 -->
            <verbose>true</verbose>
            <!-- 是否覆蓋 -->
            <overwrite>false</overwrite>
            <!-- 自動生成的配置 -->
            <configurationFile>
                src/main/resources/mybatis-generator.xml</configurationFile>
        </configuration>
</plugin>

generator配置

mybatis-generator.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!--mysql 連接數據庫jar 這里選擇自己本地位置-->
    <classPathEntry
            location="D:\Application\apache-maven-3.3.9\localRepository\mysql\mysql-connector-java\5.1.46\mysql-connector-java-5.1.46.jar"/>
    <context id="testTables" targetRuntime="MyBatis3">
        <commentGenerator>
            <!-- 是否去除自動生成的注釋 true:是 : false:否 -->
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>
        <!--數據庫連接的信息:驅動類、連接地址、用戶名、密碼 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/woke_cloud_property?serverTimezone=UTC&amp;tinyInt1isBit=false"
                        userId="root"
                        password="root">
        </jdbcConnection>
        <!-- 默認false,把JDBC DECIMAL 和 NUMERIC 類型解析為 Integer,為 true時把JDBC DECIMAL 和
           NUMERIC 類型解析為java.math.BigDecimal -->

        <javaTypeResolver type="other.MyTypeResolver">
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>

        <!-- targetProject:生成PO類的位置 -->
        <javaModelGenerator targetPackage="cn.keats.project.camp.entity"
                            targetProject="src/main/java">
            <!-- enableSubPackages:是否讓schema作為包的后綴 -->
            <property name="enableSubPackages" value="false"/>
            <!-- 從數據庫返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!-- targetProject:mapper映射文件生成的位置
           如果maven工程只是單獨的一個工程,targetProject="src/main/java"
           若果maven工程是分模塊的工程,targetProject="所屬模塊的名稱",例如:
           targetProject="ecps-manager-mapper",下同-->
        <sqlMapGenerator targetPackage="mapper"
                         targetProject="src/main/resources">
            <!-- enableSubPackages:是否讓schema作為包的后綴 -->
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>
        <!-- targetPackage:mapper接口生成的位置 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="cn.keats.project.camp.mapper"
                             targetProject="src/main/java">
            <!-- enableSubPackages:是否讓schema作為包的后綴 -->
            <property name="enableSubPackages" value="false"/>
        </javaClientGenerator>
        <!-- 指定數據庫表  多個表示,可用多個table標簽-->
        <table tableName="test_tinyint"
               enableCountByExample="false"
               enableUpdateByExample="false"
               enableDeleteByExample="false"
               enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>
    </context>
</generatorConfiguration>

其他逆向工程的工具

easycode通過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);


免責聲明!

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



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