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

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

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

    PC的blog

    Finding... Thinking... Solving...

    BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
      9 Posts :: 0 Stories :: 54 Comments :: 0 Trackbacks
    前段時間寫了本書《Hibernate 3和Java Persistence API 程序開發(fā)從入門到精通》,書中著重介紹了在Hibernate/JPA中使用Annotation。最近有讀者來信詢問UserType,再加上最近看到有的人在項目中濫用Hibernate的user type,想在這里說幾句。

    使用UserType首先要弄清楚它的目的。大家知道Hibernate解決的主要是對象數(shù)據(jù)庫阻抗失衡的問題,也就是如何將一個或多個對象保存到一個或多個數(shù)據(jù)庫表格中。這其中有很多方法,其實大部分情況下采用@Embeddable和@Embedded就可以解決問題了,只有嵌入對象方式無法滿足要求時,或者是Hibernate默認(rèn)的持久化方式無法滿足要求時,才應(yīng)該考慮UserType??傊涀∫粋€原則,不到山窮水盡,不要輕易使用UserType。還有一個要慎重考慮使用UserType的原因是:一旦采用了UserType,你的項目就脫離了JPA,而直接和Hibernate耦合在一起了。

    擴展UserType主要分為兩種:
    1. immutable
    2. mutable
    今天我先舉個immutable的例子。

    Java 5提出了一個新的enum類,JPA提供的標(biāo)準(zhǔn)方法是保存enum的name或者是ordinal。這種默認(rèn)方式能夠滿足新開發(fā)的項目,但是對于一些老項目翻新并不一定適用。下面我們來看一個例子:

    public class Status {

        
    public static final int ACTIVATED = 5;
        
    public static final int DEACTIVATED = 6;
    }

    這個是在java5之前常用的常量定義方法,老項目數(shù)據(jù)庫里面已經(jīng)保存了很多的5啊6的。現(xiàn)在要把Status改寫成enum,而且不希望修改數(shù)據(jù)庫中已有的數(shù)據(jù),怎么做?第一反應(yīng),status enum可以這么寫:

    public enum Status {
            ACTIVATED,
            DEACTIVATED;
    }

    持久化enum的name屬性是肯定不用考慮了,ordinal屬性呢?這里要保存的可是5和6,而Status enum只有兩個實體,他們的ordinal只是0和1。而且項目中還會有其他很多類似的常量類需要改寫成enum,JPA的默認(rèn)方式無法完成任務(wù),這時候可以開始考慮使用UserType了。

    先定義一個接口,這樣可以使用一個UserType支持所有類似的enum:

    public interface DescriptionID {

        String getDescription();

        
    int getId();
    }

    然后改寫Status enum:

    public enum Status implements DescriptionID {

        ACTIVATED(
    5"This object is activated"),  
        DEACTIVATED(
    9"This object is deactivated");

        
    private Integer id;
        
    private String description;
        
    private static List<Status> list;

        
    static {
            list 
    = new ArrayList<Status>(2);
            list.add(ACTIVATED);
            list.add(DEACTIVATED);
        }

        
    private Status(int statusNr, String description) {
            
    this.id = statusNr;
            
    this.description = description;
        }

        
    public String getDescription() {

            
    return this.description;
        }

        
    public Integer getId() {
            
    return id;
        }

        
    public static List<Status> getAll() {
            
    return list;
        }

        
    public static Status findById(Integer id) {
            
    for (Status status : getAll()) {
                
    if (id == status.getId()) {
                    
    return status;
                }
            }
            
    return null;
        }

    }

    注意這里每個enum都必須有兩個static方法,這些方法名必須在所有的enum中保持一致。List()方法是為了方便獲取所有的Status常量,例如在用戶界面通過ComboBox展示,findById()方法是為了通過給定Id獲得對應(yīng)的Enum實例。其中findById()方法參數(shù)一定要是Integer,原因后面會講到。

    下面編寫DescriptionIDUserType:



    public class DescriptionIDUserType implements UserType, ParameterizedType {

        
    private Class enumClass;

        
    public void setParameterValues(Properties parameters) {
            
    try {
                enumClass 
    = ReflectHelper.classForName(parameters.getProperty("class"));
            } 
    catch (ClassNotFoundException e) {
                
    // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        }
        
        
    public Object assemble(Serializable cached, Object arg1)
                
    throws HibernateException {

            
    return cached;
        }
        
        
    /*
         * (non-Javadoc)
         * 
         * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
         
    */
        
    public Object deepCopy(Object value) throws HibernateException {
            
    // TODO Auto-generated method stub
            return value;
        }

        
    /*
         * (non-Javadoc)
         * 
         * @see org.hibernate.usertype.UserType#disassemble(java.lang.Object)
         
    */
        
    public Serializable disassemble(Object value) throws HibernateException {
            
    // TODO Auto-generated method stub
            return (Serializable) value;
        }

        
    /*
         * (non-Javadoc)
         * 
         * @see org.hibernate.usertype.UserType#equals(java.lang.Object,
         *      java.lang.Object)
         
    */
        
    public boolean equals(Object id1, Object id2) throws HibernateException {
            
    if (id1 == id2) {
                
    return true;
            }
            
    if (id1 == null || id2 == null) {
                
    return false;
            }

            
    final DescriptionID did1 = (DescriptionID) id1;
            
    final DescriptionID did2 = (DescriptionID) id2;

            
    return did1.getId() == did2.getId()
                    
    && StringUtils.equals(did1.getDescription(), did2
                            .getDescription());
        }

        
    /*
         * (non-Javadoc)
         * 
         * @see org.hibernate.usertype.UserType#hashCode(java.lang.Object)
         
    */
        
    public int hashCode(Object value) throws HibernateException {
            
    // TODO Auto-generated method stub
            return value.hashCode();
        }

        
    /*
         * (non-Javadoc)
         * 
         * @see org.hibernate.usertype.UserType#isMutable()
         
    */
        
    public boolean isMutable() {
            
    // TODO Auto-generated method stub
            return false;
        }

        
    /*
         * (non-Javadoc)
         * 
         * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet,
         *      java.lang.String[], java.lang.Object)
         
    */
        
    public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner)
                
    throws HibernateException, SQLException {
            
    try {
                
    int id = resultSet.getInt(names[0]);
                
    if (resultSet.wasNull()) {
                    
    return null;
                }
                
    return enumClass.getMethod("findById"new Class[] { Integer.class })
                        .invoke(
    null, id);
            } 
    catch (IllegalArgumentException e) {
                
    // TODO Auto-generated catch block
                e.printStackTrace();
            } 
    catch (SecurityException e) {
                
    // TODO Auto-generated catch block
                e.printStackTrace();
            } 
    catch (IllegalAccessException e) {
                
    // TODO Auto-generated catch block
                e.printStackTrace();
            } 
    catch (InvocationTargetException e) {
                
    // TODO Auto-generated catch block
                e.printStackTrace();
            } 
    catch (NoSuchMethodException e) {
                
    // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
    return null;
        }

        
    /*
         * (non-Javadoc)
         * 
         * @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement,
         *      java.lang.Object, int)
         
    */
        
    public void nullSafeSet(PreparedStatement statement, Object value, int index)
                
    throws HibernateException, SQLException {
            
    if (value == null) {
                statement.setNull(index, Hibernate.INTEGER.sqlType());
            } 
    else {
                DescriptionID dID 
    = (DescriptionID) value;
                statement.setInt(index, dID.getId());
            }
        }

        
    /*
         * (non-Javadoc)
         * 
         * @see org.hibernate.usertype.UserType#replace(java.lang.Object,
         *      java.lang.Object, java.lang.Object)
         
    */
        
    public Object replace(Object original, Object arg1, Object arg2)
                
    throws HibernateException {
            
    // TODO Auto-generated method stub
            return original;
        }

        
    /*
         * (non-Javadoc)
         * 
         * @see org.hibernate.usertype.UserType#returnedClass()
         
    */
        
    public Class returnedClass() {
            
    return DescriptionID.class;
        }

        
    /*
         * (non-Javadoc)
         * 
         * @see org.hibernate.usertype.UserType#sqlTypes()
         
    */
        
    public int[] sqlTypes() {
            
    return new int[]{Hibernate.INTEGER.sqlType()};
        }


    }

    我們的這個UserType是要支持實現(xiàn)DescriptionID的各種不同的enum,而enum是沒法繼承的。所以我們需要用戶給出具體的參數(shù),以進一步確定到底是哪個enum類。這也就導(dǎo)致了,我們的這個類需要實現(xiàn)ParameterizedType接口。

    由于enum類本身是immutable的,所以這個UserType的實現(xiàn)類相對比較簡單,主要的兩個方法是
    nullSafeGet和nullSafeSet。在nullSaftGet中我們使用Java Reflection并借助用戶給出的enum類參數(shù)直接調(diào)用該enum類的findById()方法,這樣我們就可以使用數(shù)據(jù)庫中的integer找到對應(yīng)的enum實例。注意,由于使用了Java Reflection,所以findById()方法參數(shù)必須是Integer而非int。 在nullSafeSet中,我們則通過DescriptionID接口直接獲取enum實例的id屬性,并且將它保存到數(shù)據(jù)庫中去。

    最后看看怎么使用這個UserType:

    @TypeDefs({@TypeDef(name = "status", typeClass = DescriptionIDUserType.class
                        parameters 
    = {@Parameter(name = "class", value = "com.yourpackage.Status")})})
    @Entity
    public class SomeObject {

        
    private Integer objectId;
        
    private Status status;

        @Id
       
    @GeneratedValue(strategy=GenerationType.AUTO)   
       
    public Integer getObjectId() {
            
    return objectId;
        }

        
    public void setObjectId(Integer objectId) {
            
    this.objectId = objectId;
        }

        @Type(type 
    = "status")
        
    public Status getStatus() {
            
    return status;
        }

        
    public void setStatus(Status status) {
            
    this.status = status;
        }
    }

    其中值得講講的就是定義Type時使用的parameter,"class"參數(shù)是我們自己定義的,該參數(shù)為DescriptionIDUserType提供了具體的enum類。前面已經(jīng)講過了,DescriptionIDUserType就是在運行時態(tài)利用這個參數(shù)自定義enum與數(shù)據(jù)庫之間的持久化邏輯。

    使用這個UserType之后,我們就可以在確保數(shù)據(jù)庫數(shù)據(jù)不變的情況下,成功地將類型不保險的常量類改寫成enum,而且這個UserType支持所有實現(xiàn)了
    DescriptionID接口的enum類。

    類似的情況朋友們可以自由發(fā)揮了。

    關(guān)于Annotation和Usertype的相關(guān)知識請參考我寫的《Hibernate 3和Java Persistence API 程序開發(fā)從入門到精通》





    聲明:本文版權(quán)歸作者所有,如需轉(zhuǎn)載請注明出處。

    posted on 2008-03-21 20:14 polygoncell 閱讀(2960) 評論(4)  編輯  收藏

    Feedback

    # re: Hibernate user type 2008-03-21 20:22 333333333
    人家用你管得著嗎?  回復(fù)  更多評論
      

    # re: Hibernate user type 2008-03-21 21:57 ci
    不錯...  回復(fù)  更多評論
      

    # re: Hibernate user type 2008-03-21 22:41 葛京
    謝謝捧場,能用得上就好。  回復(fù)  更多評論
      

    # re: Hibernate user type 2008-03-29 00:19 polygoncell

    本書的命題是“入門和精通”,網(wǎng)上提供的章節(jié)僅僅是入門級別的內(nèi)容,是為那些完全沒有Hibernate基礎(chǔ)的同學(xué)準(zhǔn)備的。 那些已經(jīng)了解Hibernate的同學(xué)一定會覺得這些章節(jié)很乏味,這是很正常的,因為你們已經(jīng)掌握了這些入門級別的內(nèi)容,再看一遍,自然乏味。但是請你們?yōu)槟切膩頉]有接觸過Hibernate的同學(xué)考慮一下,他們非常需要一個相對淺顯易懂的臺階來幫助他們“入門”。這就是我撰寫前幾章入門內(nèi)容的初衷。

    對于那些已經(jīng)了解Hibernate的朋友們,請你們靜下心來閱讀后面深入內(nèi)核的章節(jié),在這些章節(jié)中,我是從構(gòu)架的角度講解了Hibernate的幾個主要的模塊,舉例印證,圖文并茂,大部分內(nèi)容源于實際項目。如果通讀完全書,還有朋友認(rèn)為這本書“不怎么樣”,那么我作為這本書的作者,在這里誠心誠意的期盼著你們的寶貴意見,對于正確的意見,我將會在本書的后續(xù)版本中加以采納。

    不論如何,非常感謝大家對本書的關(guān)注。  回復(fù)  更多評論
      


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲av无码专区在线电影| 亚洲免费日韩无码系列| 亚洲AV日韩精品一区二区三区| 免费夜色污私人影院网站| 亚洲国产美国国产综合一区二区| 毛片免费视频在线观看| 暖暖免费中文在线日本| 亚洲AV日韩AV天堂久久| 巨胸喷奶水视频www网免费| 美女露隐私全部免费直播| 亚洲AV日韩AV永久无码绿巨人| 国产资源免费观看| 久久精品视频免费看| 国产精品亚洲va在线观看| 亚洲色大成网站www永久一区| 欧洲乱码伦视频免费| 高清永久免费观看| 亚洲中文字幕无码中文字| 亚洲精品午夜国产VA久久成人| 大陆一级毛片免费视频观看| 99热在线日韩精品免费| 亚洲日韩国产AV无码无码精品| 亚洲人成网站在线观看播放| 免费高清av一区二区三区| 久久免费国产视频| 国产精品小视频免费无限app| 在线亚洲午夜片AV大片| 国产AV无码专区亚洲AV男同| 免费无码黄动漫在线观看| 最近免费中文字幕大全免费版视频 | 一级黄色免费网站| 亚洲熟妇无码AV不卡在线播放| 亚洲成AV人片一区二区| 亚洲A∨午夜成人片精品网站| 国产啪精品视频网免费| 久久久99精品免费观看| ssswww日本免费网站片| 美女被暴羞羞免费视频| 亚洲精品无码国产片| 亚洲人精品亚洲人成在线| 91亚洲自偷在线观看国产馆|