<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    stone2083

    ibatis支持枚舉類型

    很多應用中,數據庫表結構都會存在一些狀態字段。在關系性數據庫中,一般會用VARCHAR類型。使用ibatis的應用,傳統做法,往往會使用String的屬性,與之對應。
    例如一張member表,結構設計如下:

    其中status為狀態字段。

    ibatis中,使用class MemberPO 與之mapping,設計往往如下:
    public class MemberPO implements Serializable {
        
    private Integer id;
        
    private String loginId;
        
    private String password;
        
    private String name;
        
    private String profile;
        
    private Date gmtCreated;
        
    private Date gmtModified;
        
    private String status;

       
    //getter/setters

    缺點:
    1)不直觀,沒人會知道status具體有哪些值。在缺乏文檔,并且歷史悠久的系統中,只能使用“select distinct(status) from member”,才能得到想要的數據。如果是在千萬級數據中,代價太大了;
    2)類型不安全,如果有人不小心拼寫錯誤,將會導致錯誤狀態。假設上面列子中,status只允許ENABLED/DISABLED,如果一不小心,memberPO.setStatus("ENABLEDD"),那么將會造成臟數據。

    既然jdk5之后,引入了enum,是否可以讓ibatis支持enum類型呢?事實上,最新的ibatis版本,已經支持enum類型(本文使用的是2.3.4.726版本--mvn repsitory上最新的版本)。
    以上代碼可以修改成:
    1)Status類:
    public enum Status {

        
    /** enabled */
        ENABLED,

        
    /** disabled */
        DISABLED;

    2)MemberPO類:
    public class MemberPO implements Serializable {
        
    private Integer id;
        
    private String loginId;
        
    private String password;
        
    private String name;
        
    private String profile;
        
    private Date gmtCreated;
        
    private Date gmtModified;
        
    private Status status;

        
    //getter/setters

    除此之外,其他均無需改動。
    為什么呢?ibatis如何知道VARCHAR/Enum的mapping呢?
    看過ibatis源碼的同學,知道,ibatis是通過jdbcType/javaType得到對應的TypeHandler做mapping處理的。ibatis有基本類型的TypeHandler,比如StringTypeHandler,IntegerTypeHandler等等。在最新版本中,為了支持enum,增加了一個EnumTypeHandler。

    并且在TypeHandlerFactory中,加了對enum類型的判斷,請看:
    public TypeHandler getTypeHandler(Class type, String jdbcType) {
        Map jdbcHandlerMap 
    = (Map) typeHandlerMap.get(type);
        TypeHandler handler 
    = null;
        
    if (jdbcHandlerMap != null) {
          handler 
    = (TypeHandler) jdbcHandlerMap.get(jdbcType);
          
    if (handler == null) {
            handler 
    = (TypeHandler) jdbcHandlerMap.get(null);
          }
        }
        
    if (handler == null && type != null && Enum.class.isAssignableFrom(type)) {
          handler 
    = new EnumTypeHandler(type);
        }
        
    return handler;
      }
    ibatis使用了取巧的方法,當取不到基本類型的handler時候,判斷javaType是否是Enum類型--Enum.class.isAssignableFrom(type),如果是,則使用 EnumTypeHandler進行mapping處理。

    為什么說它取巧,原因是早期ibatis設計過程中,自定義的接口無法得到具體的java class type。故早期的ibatis中,要實現對enmu的支持,非常苦難。而新版本中,為了達到這個功能,作者直接修改了TypeHandlerFactory的實現,打了一個補丁,如下:
    if (handler == null && type != null && Enum.class.isAssignableFrom(type)) {
          handler 
    = new EnumTypeHandler(type);
    }
    這個設計有悖于和早前的設計思想。早期,TypeHandler都是通過public void register(Class type, String jdbcType, TypeHandler handler)方式事先注冊到factory中的,而這次,是在運行期,通過new方法動態得到EnumTypeHandler。
    當然,新版本ibatis能支持enum,已經是一件開心的事情了。

    Status枚舉類除了描述狀態,就足夠了嗎?回想起很多應用,我是做web開發的,在view層(velocity,jsp,等),見多了類似這樣的代碼:
    #if($member.getStatus()==Status.ENABLED)開通#elseif($member.getStatus()==Status.DISABLED)關閉#end

    <select>
      
    <option value="ENABLED" #if($member.getStatus()==Status.ENABLED) selected="selected"#end >開通</option>
      
    <option value="DISABLED" #if($member.getStatus()==Status.DISABLED) selected="selected"#end >關閉</option>
    </select>

    web層需要多少個頁面,就需要維護多少份這樣的代碼;以后每添加/刪除一種狀態,多個地方都需要修改,還要擔心邏輯不一致。

    而事實上,關于狀態的信息描述,按照職責分,就應該由枚舉類來維護:
    1)制定一個接口,EnumDescription.java
    public interface EnumDescription {

        
    public String getDescription();

    }
    2)寫一個ResourceBundleUtil.java,通過Properties文件得到描述信息:
    public class ResourceBundleUtil {

        
    private ResourceBundle resourceBundle;

        
    public ResourceBundleUtil(String resource) {
        
    this.resourceBundle = ResourceBundle.getBundle(resource);
        }

        
    public ResourceBundleUtil(String resource, Locale locale) {
        
    this.resourceBundle = ResourceBundle.getBundle(resource, locale);
        }

        
    public String getProperty(String key) {
        
    return resourceBundle.getString(key);
        }

    }
    3)Status等枚舉類實現EnumDescription:
    public enum Status implements EnumDescription {

        
    /** enabled */
        ENABLED,

        
    /** disabled */
        DISABLED;

        
    private static ResourceBundleUtil util = new ResourceBundleUtil(Status.class.getName());

        
    public String getDescription() {
           
    return util.getProperty(this.toString());
        }

    }

    這樣,有什么好處:
    1)通過Properties文件,支持國際化。
    2)描述信息統一由自己來維護,方便維護,并且顯示層邏輯簡化,如:
    $member.getStatus().getDescription()

    <select>
      #foreach($status in $Status.values())
        
    <option value="$status" #if($member.getStatus()==$status)selected="selected"#end >$status.getDescription()</option>
      #end
    </select>

    ##############################################################################
    那么使用老版本ibatis的客戶怎么辦呢?就像我們公司使用ibatis 2.3.0,難道只能眼饞著?解決方案:
    1)升級到最新版本。 :)
    2)ibatis提供了TypeHandler/TypeHandlerCallback接口,針對每種枚舉類型,寫相應的TypeHandler/TypeHandlerCallback的接口實現即可--工作量大,重復的勞動力。
    主要是早期ibatis TypeHandler無法得到javaType類型,無法從jdbc value轉成對應的枚舉。在我看來,TypeHandler是作mapping用的,它至少有權知道javaType。
    3)實現偽枚舉類型(允許繼承)來實現狀態類型安全,而拋棄jdk5的方式--不方便日后升級。


    不知道大家是否還有更好的方案?

    本文涉及演示代碼如下:
    演示代碼
    workspace file encoding:utf-8
    build tool: maven
    repository:spring/2.5.5;ibatis/2.3.4.726

    posted on 2008-11-05 23:08 stone2083 閱讀(6731) 評論(2)  編輯  收藏 所屬分類: java

    Feedback

    # re: ibatis支持枚舉類型 2013-04-27 11:02 33

    3  回復  更多評論   

    # re: ibatis支持枚舉類型[未登錄] 2013-09-25 10:26 test

    這個默認的 EnumTypeHandler還是有局限的,他將Enum跟數據庫里面的數據映射是根據Enum.valueOf(type, (String)s);然后Enum又是直接使用Enum.valueOf(type, (String)s)接口來處理。再進去就是用Class里面的enumConstantDirectory().get(name)來獲取Enum對象。這種就必須要求數據庫存儲的String是Enum的key值。限制得比較死。  回復  更多評論   

    主站蜘蛛池模板: 亚洲免费视频网址| 国产免费变态视频网址网站| 亚洲国产视频久久| 亚洲成AV人网址| 日本高清高色视频免费| 亚洲熟伦熟女专区hd高清| 日韩精品亚洲专区在线观看| 无码精品人妻一区二区三区免费看 | 亚洲精品色在线网站| 久久亚洲中文字幕精品一区四| 午夜免费福利视频| 亚洲AV无码专区亚洲AV桃| 久久精品亚洲综合一品| 狼友av永久网站免费观看| 你懂的在线免费观看| 亚洲成AV人片高潮喷水| 亚洲2022国产成人精品无码区| 成人免费视频国产| 91精品视频在线免费观看| 四虎影视在线看免费观看| 亚洲六月丁香六月婷婷蜜芽| 亚洲精品综合久久| 日本在线高清免费爱做网站| 一级黄色免费网站| 亚洲一久久久久久久久| 亚洲丝袜美腿视频| 亚洲国产成人精品无码久久久久久综合 | 亚洲av日韩av无码黑人| 国产免费拔擦拔擦8x| 午夜免费1000部| 中国一级特黄高清免费的大片中国一级黄色片| 亚洲成人动漫在线观看| 国产成人A人亚洲精品无码| 国产精品麻豆免费版| 成年黄网站色大免费全看| 中文字幕无码一区二区免费| 国产亚洲精品精品精品| 久久精品国产亚洲AV久| 亚洲成色www久久网站夜月| 亚洲国产精品日韩专区AV| 国内大片在线免费看|