日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Java、Mysql、MyBatis 中枚举 enum 的使用

發布時間:2023/12/9 数据库 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java、Mysql、MyBatis 中枚举 enum 的使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

From: https://yulaiz.com/java-mysql-enum/

Java 和 MySql 中都有枚舉的概念,合理的使用枚舉,可以讓代碼閱讀和數據庫數據查詢更加直觀、高效。那么我們怎么使用呢,什么時候使用,兩者之間怎么進行數據關聯呢?(本文使用 MyBatis 做為 Java 與 MySql 之間的關聯)

文章目錄 [hide]

  • 1 1. 當年我們怎么定義狀態
    • 1.1 1.1 數據庫設計
    • 1.2 1.2 Java Bean 代碼
    • 1.3 1.3 MyBatis 代碼
    • 1.4 1.4 代碼效果
  • 2 2. 現在我們怎么定義狀態
    • 2.1 2.1 Java Bean 代碼
    • 2.2 2.2 數據庫設計
    • 2.3 2.3 MyBatis 代碼
    • 2.4 2.4 代碼效果
  • 3 3. 怎么把當年定義的狀態改成使用枚舉
    • 3.1 3.1 數據庫設計
    • 3.2 3.2 Java Bean 代碼
    • 3.3 3.3 MyBatis 代碼
      • 3.3.1 3.3.1 內置枚舉轉換器
        • 3.3.1.1 3.3.1.1 EnumTypeHandler
        • 3.3.1.2 3.3.1.2 EnumOrdinalTypeHandler
      • 3.3.2 3.3.2 自定義枚舉轉換器
      • 3.3.3 3.3.3 在 Mapper.xml 中配置自定義的枚舉轉換器
        • 3.3.3.1 方法1:修改指定xml文件,指定的Mapper生效
        • 3.3.3.2 方法2:全局指定枚舉轉換器,無需單獨修改Mapper.xml
        • 3.3.3.3 方法3:不使用枚舉轉換器
  • 4 4. 枚舉到底好不好用
    • 4.1 4.1 Java 枚舉的實現
      • 4.1.1 4.1.1 基礎聲明、屬性、構造函數
      • 4.1.2 4.1.2 常用方法
        • 4.1.2.1 4.1.2.1 name() 方法
        • 4.1.2.2 4.1.2.2 ordinal() 方法。
        • 4.1.2.3 4.1.2.3 toString() 方法
        • 4.1.2.4 4.1.2.4 equals(Object other) 方法
        • 4.1.2.5 4.1.2.5 compareTo(E o) 方法
        • 4.1.2.6 4.1.2.6 values() 方法
        • 4.1.2.7 4.1.2.7 valueOf(String name) 方法
      • 4.1.3 4.1.3 比較兩個枚舉值是否一致
    • 4.2 4.2 MySql 中的枚舉
      • 4.2.1 4.2.1 DDL 操作效率
        • 4.2.1.1 4.2.1.1 新增一個枚舉狀態
        • 4.2.1.2 4.2.1.2 修改一個枚舉狀態
        • 4.2.1.3 4.2.1.3 刪除一個枚舉狀態
      • 4.2.2 4.2.2 查詢效率
  • 5 5. 枚舉使用總結
  • 6 6. 參考鏈接

1. 當年我們怎么定義狀態

我們定義狀態變量時,通常需要約定幾個狀態,比如交易訂單中,我們就有常見的創建、交易中、支付成功、支付失敗等等狀態,當年我們都是約定好 0,1,2,3,4,5 這樣的字段來表示上述幾個字段。

1.1 數據庫設計

例如我們的數據庫設計時,直接這樣描述:

CREATE TABLE `order_test` (`id` int(20) NOT NULL AUTO_INCREMENT,`status` int(1) NOT NULL COMMENT '0-創建,1-支付中,2-支付成功,3-支付失敗,4-取消訂單',PRIMARY KEY (`id`) USING BTREE )

SQL

0-創建,1-支付中,2-支付成功,3-支付失敗,4-取消訂單 這就是我們的約定了。

當然也有惡心的設計數據庫直接使用 varchar 數據類型,這就更惡心了,搜索都不好了。

1.2 Java Bean 代碼

在 Java 中我們代碼這樣寫:

public class OrderInfo {private int id;//0-創建,1-支付中,2-支付成功,3-支付失敗,4-取消訂單private int status; }

Java

有時候牛逼點,我們定義點常量:

public interface class OrderConstants {//創建int ORDER_STATUS_CREATE = 0;//支付中int ORDER_STATUS_PAYING = 1;//支付成功int ORDER_STATUS_IN_PROGRESS = 2;//支付失敗int ORDER_STATUS_FAILED = 3;//取消訂單int ORDER_STATUS_REVERSED = 4; }

Java

1.3 MyBatis 代碼

然后用 MyBatis 插入查詢什么的時候也簡單:

@Mapper public interface OrderMapper {int addOrder(@Param("item") OrderInfo info);OrderInfo getOrderById(@Param("id") String id); }

Java

<insert id="addOrder" parameterType="com.yulaiz.model.order.entity.OrderInfo">INSERT INTO order_test ( status )VALUES (#{item.status}) </insert> <select id="getOrderById" resultType="com.yulaiz.model.order.entity.OrderInfo">SELECT id, statusFROM order_testWHERE id = #{id} </select>

XML

1.4 代碼效果

我們最后拿到的就是 0,1,2,3,4 這樣的數值來表示訂單狀態了,當然現在的例子實在簡單,實際項目中,那可不僅僅就這么 0-4,還有很多,并且一個訂單的狀態,可不僅僅就這些,還有其他字段來描述,那么在一些復雜的查詢中,那就亂套了,一堆狀態,都是數字,沒辦法一個個查吧,這可是真麻煩。

2. 現在我們怎么定義狀態

2.1 Java Bean 代碼

一般在我設計枚舉字段的時候,我會先設計 Java 部分的枚舉字段,因為嘛,我覺得這樣粘貼復制方便一點:

public enum OrderStatus {CREATE("創建"),PAYING("支付中"),IN_PROGRESS("支付成功"),FAILED("支付失敗"),REVERSED("取消訂單");private String value;OrderStatus(String value) {this.value = value;}public String getValue() {return value;} }

Java

在使用中也很簡單,首先 Java Bean 設計時直接將數據類型改為 OrderStatus :

public class OrderInfo {private int id;private OrderStatus status; }

Java

賦值的時候使用:

orderInfo.setStatus(OrderStatus.CREATE);

Java

2.2 數據庫設計

在 Mysql 中這樣描述 enum 字段:

CREATE TABLE `order_test` (`id` int(20) NOT NULL AUTO_INCREMENT,`status` enum('CREATE','PAYING','IN_PROGRESS','FAILED','REVERSED') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'CREATE' COMMENT 'CREATE-創建,PAYING-支付中,IN_PROGRESS-支付成功,FAILED-支付失敗,REVERSED-取消訂單',PRIMARY KEY (`id`) USING BTREE )

SQL

2.3 MyBatis 代碼

接著 MyBatis 中插入查詢完全不用修改,還是上次那個原樣就ok,是不是很簡單。

2.4 代碼效果

這樣一來我們在 Java 代碼中就可以直接看到這個狀態是 CREATE 或者 PAYING 或者其他狀態,在sql查詢中也會顯示 CREATE 或者 PAYING 或者其他狀態,清晰明了,不需要再去一個個的查字段定義,非常方便閱讀。

其中Java代碼里枚舉類有一個隱藏的屬性叫 name 就是我們定義時候使用的 CREATE("創建"),PAYING("支付中") 當中的 CREATE 和 PAYING ,MyBatis在插入數據庫的時候,會自動使用這個 name 屬性作為賦值,而查詢的時候也是通過數據庫查詢的內容和 name 屬性進行匹配。

3. 怎么把當年定義的狀態改成使用枚舉

好了,由于本人比較懶,發現枚舉的好處之后就覺得,當年寫的到底是什么垃圾代碼,由此也就想把之前定義的都替換成枚舉。

3.1 數據庫設計

首先,咱從底層入手,先看看數據庫。

要想修改成枚舉,那么我就要先新增一個枚舉字段,然后根據原有的映射,來分別 update 對應數據,但是這樣是很糟糕的操作:

  • 麻煩,當數據量大時,大量 update 操作效率很慢。
  • 修改后原有代碼邏輯沒有修改完整,導致出錯。
  • 那么數據庫就先不改了,咱直接把新功能用上枚舉吧,之前的代碼不改動了,新功能的 Java 部分直接用上枚舉,盡量讓自己寫代碼舒服點,看著爽一些。

    3.2 Java Bean 代碼

    我們仍舊想使用 orderInfo.setStatus(OrderStatus.CREATE); 的方式進行賦值,但是現在數據庫中的數據是 0,1,2... 跟枚舉類 OrderStatus 的 name屬性 不能對應上了。

    首先我們還是先寫 Java 的枚舉,由于這次要跟數據庫對應上,數據結構就有點區別了:

    public enum OrderStatus {CREATE(0, "創建"),PAYING(1, "支付中"),IN_PROGRESS(2, "支付成功"),FAILED(3, "支付失敗"),REVERSED(4, "取消訂單");private int value;private String desc;OrderStatus(int value, String desc) {this.value = value;this.desc = desc;}public int getValue() {return value;}public String getDesc() {return desc;} }

    Java

    當然,也可以:

    public enum OrderStatus {CREATE(0),PAYING(1),IN_PROGRESS(2),FAILED(3),REVERSED(4);private int value;OrderStatus(int value) {this.value = value;}public int getValue() {return value;} }

    Java

    但我覺得還是加個中文方便,那么我就想用 CREATE(0, "創建") 這種方式。

    3.3 MyBatis 代碼

    實際上這里的關鍵就是 MyBatis 了,怎么樣讓 MyBatis 知道我們在賦值 orderInfo.setStatus(OrderStatus.CREATE); 的時候用 CREATE(0, "創建") 中的 0 而不是 CREATE 呢。

    首先,我們先看看 MyBatis 是否能夠滿足我們的需求。MyBatis 內置了兩個枚舉轉換器分別是org.apache.ibatis.type.EnumTypeHandler 和 org.apache.ibatis.type.EnumOrdinalTypeHandler。

    3.3.1 內置枚舉轉換器

    3.3.1.1 EnumTypeHandler

    這是默認的枚舉轉換器,轉換器將枚舉實例轉換為實例名稱的字符串,即 name 屬性,也就是將 OrderStatus.CREATE 轉換為 CREATE。就是我們在 2.現在我們怎么定義狀態 中所使用的方式。

    3.3.1.2 EnumOrdinalTypeHandler

    這個轉換器將枚舉實例的 ordinal 屬性作為取值,這個屬性可以通過 orderInfo.getStatus().ordinal() 來獲取。

    public final int ordinal()

    Null

    Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant is assigned an ordinal of zero). Most programmers will have no use for this method. It is designed for use by sophisticated enum-based data structures, such as EnumSet and EnumMap.

    • Returns:

      the ordinal of this enumeration constant

    通過官方文檔并且通過自己的實驗來看,這個 ordinal 屬性其實是一個序號,這個序號從 0 開始,只跟定義枚舉類時的順序有關。

    當我們按照下述方式定義枚舉時:

    public enum OrderStatus {CREATE("創建"),PAYING("支付中"),IN_PROGRESS("支付成功"),FAILED("支付失敗"),REVERSED("取消訂單");//省略部分代碼... }

    Java

    其 ordinal 屬性就是跟這個先后順序有關,OrderStatus.CREATE.ordinal()==0 OrderStatus.PAYING.ordinal()==1 剛好跟我們后來自定義的 value 屬性同步了。

    但是我們不能相信這個屬性,所以 MyBatis 提供的兩種枚舉轉換器均不適用,我們也就只好繼續自定義了。

    3.3.2 自定義枚舉轉換器

    MyBatis 提供了 org.apache.ibatis.type.BaseTypeHandler 類用于我們自己擴展類型轉換器,上面的 EnumTypeHandler 和 EnumOrdinalTypeHandler 也都實現了這個接口。

    public class EnumOrderStatusHandler extends BaseTypeHandler<OrderStatus> {/*** 設置配置文件設置的轉換類以及枚舉類內容,供其他方法更便捷高效的實現** @param type 配置文件中設置的轉換類*/public EnumOrderStatusHandler(Class<OrderStatus> type) {if (type == null)throw new IllegalArgumentException("Type argument cannot be null");this.type = type;this.enums = type.getEnumConstants();if (this.enums == null)throw new IllegalArgumentException(type.getSimpleName()+ " does not represent an enum type.");}//用于定義設置參數時,該如何把Java類型的參數轉換為對應的數據庫類型@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, OrderStatus parameter, JdbcType jdbcType) throws SQLException {// 根據數據庫存儲類型決定獲取類型,本例子中數據庫中存放int類型// ps.setStringps.setInt(i, parameter.getValue());}//用于定義通過字段名稱獲取字段數據時,如何把數據庫類型轉換為對應的Java類型@Overridepublic OrderStatus getNullableResult(ResultSet rs, String columnName) throws SQLException {// 根據數據庫存儲類型決定獲取類型,本例子中數據庫中存放int類型// String i = rs.getString(columnName);int i = rs.getInt(columnName);if (rs.wasNull()) {return null;} else {// 根據數據庫中的值,定位Enum子類return locateEnum(i);}}//用于定義通過字段索引獲取字段數據時,如何把數據庫類型轉換為對應的Java類型@Overridepublic OrderStatus getNullableResult(ResultSet rs, int columnIndex) throws SQLException {// 根據數據庫存儲類型決定獲取類型,本例子中數據庫中存放int類型// String i = rs.getString(columnIndex);int i = rs.getInt(columnIndex);if (rs.wasNull()) {return null;} else {// 根據數據庫中的值,定位Enum子類return locateEnum(i);}}//用定義調用存儲過程后,如何把數據庫類型轉換為對應的Java類型@Overridepublic OrderStatus getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {// 根據數據庫存儲類型決定獲取類型,本例子中數據庫中存放int類型// String i = cs.getString(columnIndex);int i = cs.getInt(columnIndex);if (cs.wasNull()) {return null;} else {// 根據數據庫中的值,定位Enum子類return locateEnum(i);}}/*** 枚舉類型轉換** @param value 數據庫中存儲的自定義屬性* @return value對應的枚舉類*/private OrderStatus locateEnum(int value) {for (OrderStatus status : OrderStatus.values()) {if (status.getValue() == value) {return status;}}throw new IllegalArgumentException("未知的枚舉類型:" + value);} }

    Java

    類轉換器就這樣編寫,注意的是,各個重寫方法中,數據類型,用對應數據庫數據的枚舉屬性的數據類型,本次就是 value 屬性對應數據庫中的內容,所以是 int 類型,再有就是在最后的方法中,給出枚舉匹配的方法。

    3.3.3 在 Mapper.xml 中配置自定義的枚舉轉換器

    方法1:修改指定xml文件,指定的Mapper生效

    我們只需要在 insert update select 等語句中配置 typeHandler , 而 Java 文件無需改動。

    <insert id="addOrder" parameterType="com.yulaiz.model.order.entity.OrderInfo">INSERT INTO order_test ( status) VALUES (#{item.status, typeHandler=com.yulaiz.model.order.entity.enums.mybatis.EnumOrderStatusHandler}) </insert> <resultMap id="get" type="com.yulaiz.model.order.entity.OrderInfo"><result column="status" property="status"typeHandler="com.yulaiz.model.order.entity.enums.mybatis.EnumOrderStatusHandler"/> </resultMap> <select id="getOrderById" id="getOrderById" resultMap="get">SELECT id, statusFROM order_testWHERE id = #{id} </select>

    XML

    方法2:全局指定枚舉轉換器,無需單獨修改Mapper.xml

    直接在 Mybatis 的配置文件中配置自定義的類型轉換,這里我使用的 Spring-Boot,直接在 application.yml 文件中配置:

    mybatis:type-handlers-package: com.yulaiz.model.order.entity.enums.mybatis

    Yml

    方法3:不使用枚舉轉換器

    對于 insert 和 update 語句,還有一個簡單的方法:

    <insert id="addOrder" parameterType="com.yulaiz.model.order.entity.OrderInfo">INSERT INTO order_test ( status) VALUES (#{item.status.value}) </insert>

    XML

    對于 Java Bean 來說,也可以手動設置 get set 方法

    public class OrderInfo {private int id;private OrderStatus status;public int getStatus() {return status.getValue();}public void setStatus(int value) {for (OrderStatus status : OrderStatus.values()) {if (status.getValue() == value) {this.status = status;break;}}} }

    Java

    4. 枚舉到底好不好用

    枚舉這樣直觀方便,在大數據量的情況下到底好不好用呢,下面我們就這么一個問題進行分析。

    4.1 Java 枚舉的實現

    4.1.1 基礎聲明、屬性、構造函數

    java 的枚舉類 以關鍵字 enum 聲明,該關鍵字隱含著該類為 java.lang.Enum 的子類,Java編譯器在編譯枚舉類時,會生成一個相關的類,這個類就是實際的枚舉類,繼承自 java.lang.Enum 。

    public enum OrderStatus {CREATE("創建"), PAYING("支付中"), IN_PROGRESS("支付成功"), FAILED("支付失敗"), REVERSED("取消訂單"); }

    Java

    該類有兩個屬性,分別是 name 和 ordinal ,在自定義的枚舉類中,我們聲明 CREATE("創建"), PAYING("支付中"), IN_PROGRESS("支付成功"), FAILED("支付失敗"), REVERSED("取消訂單") 的時候,前面括號外部分就是 name 屬性,比如:CREATE ,而 ordinal 屬性則是我們聲明中寫的順序,從 0 開始。這兩個屬性在父類的構造函數中進行賦值,我們自定義的枚舉類中不用去費心這兩個屬性的賦值。子類中如果需要,只需要在構造方法中定義其他自定義屬性的賦值即可。

    protected Enum(String name, int ordinal) {this.name = name;this.ordinal = ordinal; }

    Java

    而 CREATE("創建") 中括號內就是我們自定義的屬性,也就是我們聲明的 value 屬性。

    4.1.2 常用方法

    4.1.2.1 name() 方法

    返回 Enum 對象的 name 屬性。

    4.1.2.2 ordinal() 方法。

    返回 Enum 對象的 ordinal 屬性。

    4.1.2.3 toString() 方法

    返回 Enum 對象的名稱,也就是 name 屬性。

    4.1.2.4 equals(Object other) 方法

    比較兩個對象是否相等。詳細用法在下方 4.1.3 比較兩個枚舉值是否一致

    4.1.2.5 compareTo(E o) 方法

    比較兩個枚舉對象的順序,在該對象小于、等于或大于指定對象時,分別返回負整數、零或正整數。詳細用法在下方 4.1.3 比較兩個枚舉值是否一致

    4.1.2.6 values() 方法

    這個方法我們查看JDK中源碼沒有看到,并且在API文檔中也沒有找到。但確實是有這么一個方法。

    在 Oracle的文檔 中可以找到這么一段話

    The compiler automatically adds some special methods when it creates an enum. For example, they have a static values method that returns an array containing all of the values of the enum in the order they are declared. This method is commonly used in combination with the for-each construct to iterate over the values of an enum type.

    大致意思就是,Java 編譯器在編譯枚舉類的時候會自動為該類加入一些靜態方法,比如說 values() ,這個方法返回一個包含這個枚舉類所有枚舉項的數組,這個數組是按照聲明的順序來排列(意味著 ordinal 屬性可以當成這個數組的下標),這個方法通常與 for-each 語句配合在遍歷枚舉值時使用。

    注意,這是一個 static 靜態方法,意味著使用的時候直接通過枚舉類來調用,比如 OrderStatus.values() 。

    4.1.2.7 valueOf(String name) 方法

    根據傳入的 name 名稱,找到相對應 name 屬性的枚舉值。

    這個方法實際上也是 Java 編譯器在編譯的時候加入的方法,在父類 java.lang.Enum 中,同樣存在 valueOf 方法,不過父類的方法是有兩個參數,而這個第一個參數就是用來指定是哪一個枚舉類,那我們在子類的時候使用這個方法就很明確是這個類本身,所以編譯器直接在編譯的時候加入了一個方法,只需要傳入 name 參數即可。

    注意,這是一個 static 靜態方法,意味著使用的時候直接通過枚舉類來調用,比如: OrderStatus.valueOf("CREATE") 。

    4.1.3 比較兩個枚舉值是否一致

    我們在實際代碼中經常根據狀態來進行流程向導,而枚舉類大部分時間就是用來表示狀態,那么我們就需要對比枚舉類是否為某個值來進行判斷:

    • 通過 switch 語句

      通過 switch 語句來判斷,簡單方便,好看:

      OrderStatus status = OrderStatus.CREATE; switch (status) {case CREATE:System.out.println("CREATE");break;case PAYING:System.out.println("PAYING");break;default:System.out.println("default"); }

      Java

    • 通過 equals() 方法

      用 String 的時候經常使用的方法:

      OrderStatus status = OrderStatus.CREATE; boolean result = status.equals(OrderStatus.CREATE);

      Java

    • 通過 == 運算符

      實際上效果跟 equals() 方法是一樣的,我們可以點進 equals() 方法的源碼查看,實際上就是使用 == 運算符來實現的:

      /*** Returns true if the specified object is equal to this* enum constant.** @param other the object to be compared for equality with this object.* @return true if the specified object is equal to this* enum constant.*/public final boolean equals(Object other) {return this==other;}

      Java

      實際使用上就更簡單了:

      OrderStatus status = OrderStatus.CREATE; if (status == OrderStatus.CREATE) {System.out.println("=="); }

      Java

    • 通過compareTo(E o) 方法

      稍微麻煩一點:

      OrderStatus status = OrderStatus.CREATE; if (status.compareTo(OrderStatus.CREATE) == 0) {System.out.println("=="); }

      Java

      ?

    4.2 MySql 中的枚舉

    首先,我們要知道對于 select 語句,枚舉對于其展示出來的數據是非常友好的,可以直觀的看到具體的含義。而枚舉的優點就是固定的有限的枚舉項,那么就需要我們在定義數據庫的時候就定義好這個枚舉可能用到的所有值,相比int類型,我們來看看對于枚舉類型 enum 的枚舉項的刪除和修改操作的效率如何。

    我在數據庫中分別創建了兩張表:order_test 、order_test_enum 。

    CREATE TABLE `order_test` (`id` int(20) NOT NULL AUTO_INCREMENT,`status` int(1) NOT NULL COMMENT '0-創建,1-支付中,2-支付成功,3-支付失敗,4-取消訂單',PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;CREATE TABLE `order_test_enum` (`id` int(20) NOT NULL AUTO_INCREMENT,`status` enum('CREATE','PAYING','IN_PROGRESS','FAILED','REVERSED') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'CREATE' COMMENT 'CREATE-創建,PAYING-支付中,IN_PROGRESS-支付成功,FAILED-支付失敗,REVERSED-取消訂單',PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

    SQL

    在兩張表中分別插入了 1000W 條數據,其數據格式就是每個枚舉項都依次循環插入,保證每個枚舉項的數量盡可能平均的分布。

    4.2.1 DDL 操作效率

    對于狀態的修改,我們一般會有幾種操作:

    • 新增一個狀態。
    • 修改一個狀態。
    • 刪除一個狀態。

    4.2.1.1 新增一個枚舉狀態

    對于 int 類型來說,這個直接無需操作了,要什么新狀態,直接 insert 的時候直接插入就行了。

    對于 enum 類型來說,這個就需要進行 DDL 操作:

    ALTER TABLE `test`.`order_test_enum` MODIFY COLUMN `status` enum('CREATE','PAYING','IN_PROGRESS','FAILED','REVERSED','TEST') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'CREATE' COMMENT 'CREATE-創建,PAYING-支付中,IN_PROGRESS-支付成功,FAILED-支付失敗,REVERSED-取消訂單,TEST-新增測試';

    SQL

    執行時間:0.008s 還不錯的速度。

    4.2.1.2 修改一個枚舉狀態

    比方說我們定義的狀態,寫錯值了,又不想將錯就錯,int 類型應該不會出現這個問題吧,奈何英文水平實在太差,拼錯了單詞,或者單詞用的不合理,我們這里假設將 PAYING 換成 PAYING1 :

    ALTER TABLE `test`.`order_test_enum` MODIFY COLUMN `status` enum('CREATE','PAYING1','IN_PROGRESS','FAILED','REVERSED','TEST') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'CREATE' COMMENT 'CREATE-創建,PAYING1-支付中,IN_PROGRESS-支付成功,FAILED-支付失敗,REVERSED-取消訂單,TEST-新增測試';

    SQL

    1265 - Data truncated for column 'status' at row 2 修改失敗,Mysql 不允許修改已經使用的枚舉項。

    那么我們想到達換枚舉值的情況就只能曲折一點,先新增一個,再 update 原有的值到新值,剛剛已經建好的TEST 值,那么我們現在就把 PAYING 修改成 TEST :

    UPDATE order_test_enum SET `status` = 'TEST' WHERE`status` = 'PAYING';

    SQL

    執行時間: 12.456s 這樣的一個時間說得過去,因為我剛剛也在 order_test 表中做了一個差不多的操作執行時間是 10.459s 。

    UPDATE order_test SET `status` = 5 WHERE`status` = 1;

    SQL

    4.2.1.3 刪除一個枚舉狀態

    同樣 int 類型無需修改,修改 enum 類型進行 DDL 操作,假設我們刪除 IN_PROGRESS 這項:

    ALTER TABLE `test`.`order_test_enum` MODIFY COLUMN `status` enum('CREATE','PAYING','FAILED','REVERSED','TEST') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'CREATE' COMMENT 'CREATE-創建,PAYING-支付中,FAILED-支付失敗,REVERSED-取消訂單,TEST-新增測試';

    SQL

    1265 - Data truncated for column 'status' at row 2 刪除失敗,這是由于MySql不允許刪除已經被使用的枚舉項。那我們刪除剛剛已經把數據改為 TEST 的 PAYING 試試:

    ALTER TABLE `test`.`order_test_enum` MODIFY COLUMN `status` enum('CREATE','IN_PROGRESS','FAILED','REVERSED','TEST') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'CREATE' COMMENT 'CREATE-創建,IN_PROGRESS-支付成功,FAILED-支付失敗,REVERSED-取消訂單,TEST-新增測試';

    SQL

    執行時間: 34.971s 這個時間是真的不快。

    4.2.2 查詢效率

    可能有些人會說枚舉對于大數據查詢是非常不友好的,畢竟是字符型。

    而實際上 Mysql 中的 enum 類型,還恰恰不是字符型,而是整型存儲。

    實際上在建立 enum 字段的時候,MySql 會根據設定的幾個字段的順序來編號,而這個編號實際上才是 MySql 真正存儲的內容,這個編號在某些文章里也會稱呼為索引值。

    在上面的例子中,建立的枚舉值分別為 'CREATE','PAYING','IN_PROGRESS','FAILED','REVERSED' ,那么他們的索引值就分別為:

    值索引值
    NULLNULL
    0
    ‘CREATE’1
    ‘PAYING’2
    ‘IN_PROGRESS’3
    ‘FAILED’4
    ‘REVERSED’5

    所以在搜索的時候 WHERE 條件中的 status = 'CREATE' 和 status = 1 是等效的,這里也要注意就是 enum 字段同樣有 NULL 值 和 ” 的情況,需要我們在定義數據類型的時候就需要注意。

    SELECTid,`status` FROMorder_test_enum WHEREid = 1 AND `status` = 1;

    SQL

    SELECTid,`status` FROMorder_test_enum WHEREid = 1 AND `status` = 'CREATE';

    SQL

    上面兩個sql查詢到的內容就是一樣的,那么同是整型,在查詢上的差距,咱就可以忽略不計了吧。

    5. 枚舉使用總結

    雖然 Java 中的枚舉比 C 或 C++ 中的 enum 更成熟,但它仍然是一個“小”功能,Java 沒有它也已經(雖然有點笨拙)存在很多年了。而本章正好說明了一個“小”功能所能帶來的價值。有時恰恰因為它,你才能夠優雅而干凈地解決問題。正如我在本書中一再強調的那樣,優雅與清晰很重要,正是它們區別了成功的解決方案與失敗的解決方案。而失敗的解決方案就是因為其他人無法理解它。

    直接引用了《Thinking in Java》這么一段話(《Thinking in Java》第四版 19章12節),很明顯,很清楚,至少在 Java 中使用枚舉是值得的。

    而對于數據庫來說,根據實際情況來構建,至少枚舉時一個特別方便的結構,如果有舊表的狀態描述字段沒有使用枚舉,請慎重是否進行改進,需要考慮存量數據的改造,以及對接代碼的改造。

    即便 MySql 中依舊使用數字來表達狀態,依然不妨礙在 Java 中改造成枚舉,具體改造的范圍需要自行斟酌,防止接口對上下游系統的不友好。

    枚舉是非常適合用來描述狀態的結構,并且不推薦使用數字來定義,請使用字符串來表達各個狀態,否則在查看代碼,查看數據庫數據的時候,還是一個數字,那我們使用枚舉的意義何在。

    總的來說,請盡量合理的使用枚舉,功能雖小,但咱們很優雅。

    6. 參考鏈接

    mysql enum類型存在大量數據的時候方便修改數據項么

    mysql 數據庫枚舉類型enum,方便添加新的枚舉項嗎?

    MySQL中的enum類型有什么優點?

    深入理解Java枚舉類型(enum)

    重新認識java(十) —- Enum(枚舉類)

    java enum(枚舉)使用詳解 + 總結

    如何在MyBatis中優雅的使用枚舉

    MYSQL中 ENUM 類型

    java枚舉enum類中的values()

    MyBatis對于Java對象里的枚舉類型處理

    MyBatis對于Java對象里的枚舉類型處理

    總結

    以上是生活随笔為你收集整理的Java、Mysql、MyBatis 中枚举 enum 的使用的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。