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

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

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

    stone2083

    ibatis支持枚舉類(lèi)型

    很多應(yīng)用中,數(shù)據(jù)庫(kù)表結(jié)構(gòu)都會(huì)存在一些狀態(tài)字段。在關(guān)系性數(shù)據(jù)庫(kù)中,一般會(huì)用VARCHAR類(lèi)型。使用ibatis的應(yīng)用,傳統(tǒng)做法,往往會(huì)使用String的屬性,與之對(duì)應(yīng)。
    例如一張member表,結(jié)構(gòu)設(shè)計(jì)如下:

    其中status為狀態(tài)字段。

    ibatis中,使用class MemberPO 與之mapping,設(shè)計(jì)往往如下:
    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

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

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

        
    /** enabled */
        ENABLED,

        
    /** disabled */
        DISABLED;

    2)MemberPO類(lèi):
    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

    除此之外,其他均無(wú)需改動(dòng)。
    為什么呢?ibatis如何知道VARCHAR/Enum的mapping呢?
    看過(guò)ibatis源碼的同學(xué),知道,ibatis是通過(guò)jdbcType/javaType得到對(duì)應(yīng)的TypeHandler做mapping處理的。ibatis有基本類(lèi)型的TypeHandler,比如StringTypeHandler,IntegerTypeHandler等等。在最新版本中,為了支持enum,增加了一個(gè)EnumTypeHandler。

    并且在TypeHandlerFactory中,加了對(duì)enum類(lèi)型的判斷,請(qǐng)看:
    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使用了取巧的方法,當(dāng)取不到基本類(lèi)型的handler時(shí)候,判斷javaType是否是Enum類(lèi)型--Enum.class.isAssignableFrom(type),如果是,則使用 EnumTypeHandler進(jìn)行mapping處理。

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

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

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

    web層需要多少個(gè)頁(yè)面,就需要維護(hù)多少份這樣的代碼;以后每添加/刪除一種狀態(tài),多個(gè)地方都需要修改,還要擔(dān)心邏輯不一致。

    而事實(shí)上,關(guān)于狀態(tài)的信息描述,按照職責(zé)分,就應(yīng)該由枚舉類(lèi)來(lái)維護(hù):
    1)制定一個(gè)接口,EnumDescription.java
    public interface EnumDescription {

        
    public String getDescription();

    }
    2)寫(xiě)一個(gè)ResourceBundleUtil.java,通過(guò)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等枚舉類(lèi)實(shí)現(xiàn)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)通過(guò)Properties文件,支持國(guó)際化。
    2)描述信息統(tǒng)一由自己來(lái)維護(hù),方便維護(hù),并且顯示層邏輯簡(jiǎn)化,如:
    $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的客戶(hù)怎么辦呢?就像我們公司使用ibatis 2.3.0,難道只能眼饞著?解決方案:
    1)升級(jí)到最新版本。 :)
    2)ibatis提供了TypeHandler/TypeHandlerCallback接口,針對(duì)每種枚舉類(lèi)型,寫(xiě)相應(yīng)的TypeHandler/TypeHandlerCallback的接口實(shí)現(xiàn)即可--工作量大,重復(fù)的勞動(dòng)力。
    主要是早期ibatis TypeHandler無(wú)法得到j(luò)avaType類(lèi)型,無(wú)法從jdbc value轉(zhuǎn)成對(duì)應(yīng)的枚舉。在我看來(lái),TypeHandler是作mapping用的,它至少有權(quán)知道javaType。
    3)實(shí)現(xiàn)偽枚舉類(lèi)型(允許繼承)來(lái)實(shí)現(xiàn)狀態(tài)類(lèi)型安全,而拋棄jdk5的方式--不方便日后升級(jí)。


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

    本文涉及演示代碼如下:
    演示代碼
    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) 評(píng)論(2)  編輯  收藏 所屬分類(lèi): java

    Feedback

    # re: ibatis支持枚舉類(lèi)型 2013-04-27 11:02 33

    3  回復(fù)  更多評(píng)論   

    # re: ibatis支持枚舉類(lèi)型[未登錄](méi) 2013-09-25 10:26 test

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

    主站蜘蛛池模板: 美女黄频a美女大全免费皮| 白白国产永久免费视频| 黄页视频在线观看免费| 亚洲色图校园春色| 国产亚洲精品精华液| 亚洲精品乱码久久久久久不卡 | 亚洲av不卡一区二区三区| 亚洲AⅤ无码一区二区三区在线| 18国产精品白浆在线观看免费| 国产在线精品一区免费香蕉| 国产成人综合久久精品亚洲| 亚洲永久在线观看| 久久亚洲精品无码aⅴ大香| 亚洲午夜福利AV一区二区无码| 国产a级特黄的片子视频免费| 在线v片免费观看视频| 中文字幕在线观看免费视频 | 国产一卡二卡四卡免费| 久久99毛片免费观看不卡| 乱淫片免费影院观看| 久久久国产亚洲精品| 亚洲免费观看在线视频| 亚洲AV永久无码精品一百度影院| 亚洲中文字幕第一页在线 | 亚洲AV无码一区二区三区性色| 亚洲国产成人精品青青草原| 亚洲今日精彩视频| 亚洲AV无码精品无码麻豆| 亚洲无av在线中文字幕| 免费国产高清视频| 免费在线观看亚洲| 免费一看一级毛片| 免费jjzz在在线播放国产| 免费一级做a爰片性色毛片| 国产在线98福利播放视频免费| 亚洲热线99精品视频| 三年片在线观看免费大全电影| 久久久久久久岛国免费播放| 免费A级毛片无码视频| 100部毛片免费全部播放完整| 亚洲最大免费视频网|