乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      自定義數(shù)據(jù)類型映射

       feimishiwo 2014-04-29

       

      自定義數(shù)據(jù)類型映射
      Hibernate提供了自定義映射類型接口,允許用戶以編程的方式創(chuàng)建自定義映射類型,以便把持久化類的任意類型的屬性映射到數(shù)據(jù)庫中。
       
      現(xiàn)在我們以一個簡單的例子來說明自定義數(shù)據(jù)類型映射的思想和用法,對于T_User對象需要增加一個email屬性用于保存用戶的郵件地址,同時要求一個用戶可以有多個郵件地址,系統(tǒng)在發(fā)送郵件時將向這些地址同時發(fā)送。
       根據(jù)我們以往的項目經(jīng)驗主要有兩種思路:
         1)、為T_User表增加email1,email2……等字段。
         2)、增加一個T_Email表,T_User表通過主鍵與之關聯(lián)。
      1種方式實現(xiàn)不夠優(yōu)雅,并且在email數(shù)量上和可查詢性上受到較大的局限,但是由于是單表操作開發(fā)難度較小,性能相對較高。
      2種方式比較完美的體現(xiàn)了設計意圖,也無email數(shù)量限制且易于查詢,但是僅僅為了一個email就增加一張表未免有些小題大做。
      其實我們可以將一個用戶的所有email信息都存在T_User表中的email字段中,每個email用分號分開,這樣我們就得到了一個大字符串,但是這就需要上層的程序邏輯處理,我們的目的是為數(shù)據(jù)邏輯層及業(yè)務邏輯層提供更加易于操作的對象。Hibernate中的UserType接口正是為我們實現(xiàn)這一目的準備的,通過實現(xiàn)該接口我們可以定義我們自己的類型,并且可加入相應的數(shù)據(jù)解析邏輯,而且他還會帶來一個好處那就是重用性(所有需要保存email的實體都可以共用該類型)。根據(jù)這里的情況如果我們將email映射為List類型將會是一個不錯的選擇,如何將email映射為List類型呢?下面我們將會看到。
      T_User

      T_User 
      id     number   <pk>
      name varchar2(50)
      age    number
      image    BLOB
      resume   CLOB
      email     varchar2(500)          
      首先我們先來認識一下UserType接口:
       
       
       
      public interface UserType{
       /**
      返回UserType所映射字段的sql類型(java.sql.Types)
      返回類型時int[],其中包含映射各自段的sql代碼
      UserType可以映射到一個或多個字段)
       **/
       public int[] getTypes();
       /**
         
      UserType.nullSafeGet()
      所返回的自定義數(shù)據(jù)類型
       **/
       public Class returnedClass();
       /**
      自定數(shù)據(jù)類型的對比方法
      此方法用于做臟數(shù)據(jù)檢查,參數(shù)x,y分別代表屬性當前值和屬性的快照值
      如果equals方法返回false,Hibernate將認為數(shù)據(jù)發(fā)生變化,并將變化更新到數(shù)據(jù)庫中
       **/
       public boolean equals(Object x,Object y) throws HibernateException;
       /**
      Hibernate加載數(shù)據(jù)時會調用該方法,該方法會從底層JDBC ResultSet讀取數(shù)據(jù),將其
      轉化為自定義類型后返回,該方法要求對可能出現(xiàn)的null值作處理,names中包含了當前自定義類型的映射字段名稱。
       **/
       public Object nullSafeGet(ResultSet rs,String[] names,Objec owner) throws HibernateException,SQLException;
       /**
         本方法將在Hibernate進行數(shù)據(jù)庫保存時被調用我們可以通過PrepareStatement將自定義數(shù)據(jù)
         寫入數(shù)據(jù)庫
       **/
       public void nullSafeSet(PrepareStatement st,Object value,int index) throws HibernateException,SQLException;
      /**
       提供自定義類型的完全復制方法本方法將用于構造返回對象,當nullSafeGet方法被調用后,我們
       獲得了自定義數(shù)據(jù)對象。在向用戶返回自定義數(shù)據(jù)之前,deepCopy方法將被調用,它將根據(jù)自定
       義數(shù)據(jù)對象構造完全拷貝,并將此拷貝返回給用戶使用。
       此時,我們就得到了自定義數(shù)據(jù)對象的兩個版本,第一個是從數(shù)據(jù)庫讀取的原始版本將由Hibernate負責維護,復制版本將由用戶使用,原版本用作稍后的臟數(shù)據(jù)檢查依據(jù);Hibernate將在臟數(shù)據(jù)檢查過程中將這兩個版本數(shù)據(jù)進行比對(通過調用equals方法),如果數(shù)據(jù)發(fā)生變化(equals將返回false),則執(zhí)行對應的持久化操作。
      **/
      public Object deepCopy(Object value) throws HibernateException;
      /**
       判斷本實例是否是可變的,Hibernate在處理不可變類型時會采取一些性能優(yōu)化措施。
      **/
       public boolean isMutable();
      }
      實現(xiàn)我們的EmailList,實現(xiàn)了UserType接口代碼如下:
      public class EmailList implements UserType{
       private List emails;
       private static final char SPLIT=”;”;
       private static final int[] TYPES=new int[]{Types.VARCHAR};
       public boolean isMutable(){
          return false;
      }
       public int[] sqlTypes(){
       return TYPES;
      }
      public Class returnedClass(){
       return List.class;
      }
      /**
       創(chuàng)建一個新的List實例,包含原有List實例所有的元素
      **/
      public Object deepCopy(Object value) throws HibernateException{
       List sourcelist=(List)value;
       List targetlist=new ArrayList();
       targetlist.addAll(sourcelist);
       return targetlist;
      }
      /**
       判斷email list是否發(fā)生變化
      **/
      public boolean equals(Object x,Object y) throws HibernateException{
       if(x==y)return ture;
       if(x!=null && y!=null){
           List xlist=(List)x;
           List ylist=(List)y;
           if(xlist.size()!=ylist.size()) return false;
           for(int i=0;i<xlist.size();i++){
            String str1=xlist.get(i).toString();
            String str2=ylist.get(i).toString();
            if(!str1.equals(str2))return false;
           }
           return true;
      }
      return false;
      }
      /**
       ResultSet中取出email字段,并將其解析為List類型后返回
      **/
      public Object nullSafeGet(ResuleSet rs String[] names,Object owner)
       throws HibernateException,SQLException{
       String value=(String)Hibernate.STRING.nullSafeGet(rs,name[0]);
       if(value!=null){
         return parse(value);
       }
       else{
         return null;
      }
      }
      /**
       List型的email信息組裝成字符串之后保存到email字段
      **/
      public void nullSafeSet(PrepareStatement st,Object value,int index)
       throws HibernateException,SQLException{
       if(value!=null){
         String str=assemble((List)value);
         Hibernate.STRING.nullSafeSet(st,str,index);
       }
       else{
         Hibernate.STRING.nullSafeSet(st,value,index);
       }
      }
      /**
       String拼裝為一個字符串,以”;”分隔
      **/
      private String assemble(List list){
       StringBuffer buffer=new StringBuffer();
       for(int i=0;i<list.size()-1;i++){
          buffer.append(list.get(i).toString()).append(SPLIT);
       }
       buffer.append(list.get(list.size()-1).toString());
       return buffer.toString();
      }
      /**
       將以”;”分隔的字符串解析為一個字符串數(shù)組
      **/
      public List parse(String value){
       List emaillist=new ArrayList();
       String[] strs=org.apache.commons.lang.StringUtils.split(SPLIT);
       for(int i=0;i<strs.length;i++){
          emaillist.add(strs[i]);
       
      }
      return emaillist;
      }
      }
       
      TUser.hbm.xml
      <hibernate-mapping>
       <class name=”com.neusoft.hibernate.entity.TUser” table=”T_USER”>
       <id…../>
       <property……/>
       <property name=”email” column=”email” type=”com.neusoft.hibernate.entity.type.EMallist” />
       </class>
      </hibernate-mapping>
       
      測試程序:
      TUser user=(TUser)session.load(TUser.class,new Integer(2));
      List list=user.getEmail();
      for(int i=0;i<list.size();i++){
       System.out.println(list.get(i));
      }
      list.add(“zhao-xin@neusoft.com”);
      Transaction trans=session.beginTransaction();
       session.save(user);
      trans.commit();
      觀察數(shù)據(jù)庫發(fā)現(xiàn)email字段已經(jīng)以”;”分隔的形勢存在,同樣在讀取時,我們也無需面對原始的”;”分隔字符串,轉而只需處理List型數(shù)據(jù)即可。
      使用UserType處理大數(shù)據(jù)對象:
      還記得我們在上一篇文章有關大數(shù)據(jù)對象映射技術中留下的伏筆嗎?現(xiàn)在我們就來兌現(xiàn),我們將使用UserType構造自定義數(shù)據(jù)類型,來給出一個大數(shù)據(jù)對象的通用解決方案(針對Oracle數(shù)據(jù)庫)。下面的StringClobType實現(xiàn)了這一目標。
      public class StringClobType implements UserType{
       private static final String ORACLE_DRIVER_NAME=”O(jiān)racle JDBC driver”;
       private static final int ORACLE_DRIVER_MAJOR_VERSION=9;
       private static final int ORACLE_DRIVER_MINOR_VERSION=0;
       
       public int[] sqlTypes(){
         return new int[]{Types.CLOB};
       }
       public Class returnedClass(){
         return String.class;
       }
       public boolean equals(Object x,Object y){
         return org.apache.commons.lang.ObjectUtils.equals(x,y);
       }
       public Object nullSafeGet(Resultset rs,String[] names,Object owner)
      throws HibernateException,SQLException{
       Clob clob=rs.getClob(names[0]);
      return (clob==null?null:clob.getSubString(1,(int)clob.length()));
      }
      public void nullSafeSet(PrepareStatement st,Object value,int index)
           throws HibernateException,SQLException{
         DatebaseMetaData dbMetaData=st.getConnection().getMetaData();
         if(value==null){
          st.setNull(index,sqlTypes()[0]);
      }
      //本實現(xiàn)只適用于Oracle數(shù)據(jù)庫9.0以上版本
      if(ORACLE_DRIVER_NAME.equals(dbMetaData.getDriverName())){
       if((dbMetaData.getDriverMajorVersion()>=ORACLE_DRIVER_MAJOR_VERSION)
           && (dbMetaData.getDriverMinorVersion()>=ORACLE_DRIVER_MINOR_VERSION)){
             try{
              //通過動態(tài)加載方式避免編譯期間對Oracle JDBC的依賴
              Class oracleClobClass=Class.forName(“oracle.sql.CLOB”);
              //動態(tài)調用createTemporary方法
              Class partypes[]=new Class[3];
              partypes[0]=Connection.class;
              partypes[1]=Boolean.class;
              partypes[2]=Integer.class;
              Method createTemporaryMethod=
      oracleClobClass.getDeclaredMethod(“createTemporary”,partypes);
              Field durationSessionField=oracleClobClass.getField(“DURATION_SESSION”);
              Object[] arglist=new Object[3];
              Connection conn=st.getConnection().getMetaData().getConnection();
              //數(shù)據(jù)庫連接類型必須為OracleConnection,某些應用服務器會使用自帶的
              //Oracle JDBC Wrapper,Weblogic,這里需要特別注意
          Class oracleConnectionClass=Class.forName(“oracle.jdbc.OracleConnection”);
              if(!oracleConnectionClass.isAssignableForm(conn.getClass())){
                throw new HibernateException(“Must be a oracle.jdbc.OracleConnection:”
      +conn.getClass.getName());
              }
              agrlist[0]=conn;
              arglist[1]=Boolean.class;
              arglist[2]=durationSessionField.get(null);
             
              Object tempClob=createTemporaryMethod.invoke(null,arglist);
              partypes[0]=Integer.TYPE;
              Method openMethod=oracleClobClass.getDeclaredMethod(“open”,partypes);
              Field modeReadWriteField=oracleClobClass.getField(“MODE_READWRITE”);
              arglist=new Object[1];
              arglist[0]= modeReadWriteField.get(null);
              openMethod.invoke(tempClob,arglist);//按讀寫模式打開Clob對象的輸入流
              Method getCharacterOutputStreamMethod=oracleClobClass.getDeclaredMethod(
                                                     “getCharacterOutputStream”,null);
              //調用getCharacterOutputStream方法
              Writer tempClobWriter=
      (Writer)getcharacterOutputStreamMethod.invoke(tempClob,null);
              //將數(shù)據(jù)寫入Clob
              tempClobWriter.write((String)value);
              tempClobWriter.flush();
              tempClobWriter.close();
              //關閉Clob
          Method closeMethod=oracleClobClass.getDeclareMethod(“close”,null);
              closeMethod.invoke(tempClob,null);
              st.setClob(index,(Clob)tempClob);
             }catch(ClassNotFoundException ce){
               throw new HibernateException(“Unable to find a require class./n”+ce.getMessage());
             } catch(NoSuchMethodException me){
               throw new HibernateException(
      “Unable to find a require method./n”+me.getMessage());
             } catch(NoSuchFieldException fe){
               throw new HibernateException(“Unable to find a require field./n”+fe.getMessage());
             } catch(IllegalAccessException ae){
               throw new HibernateException(
      “Unable to find a require method or field./n”+ae.getMessage());
             }catch(InvocationTargetException ie){
               throw new HibernateException(ie.getMessage());
             }catch(IOException oe){
               throw new HibernateException(oe.getMessage());
             }
      }else{
       throw new HibernateException(“No CLOBS support.Use driver version”+
      ORACLE_DRIVER_MAJOR+”,minor ”
      +ORACLE_DRIVER_MINOR_VERSION);
      }
      }else{
       String str=(String)value;
       StringReader r=new StringReader(str);
       st.setCharacterStream(index,r,str.length());
      }
      }
       
      public Object deepCopy(Object value){
       if(value==null)
          return null;
       return new String((String)value);
      }
      public boolean isMutable(){
       return false;
      }
      }
      上面這段代碼重點在nullSafeSet方法的實現(xiàn),在該方法中通過java reflection機制擺脫了編譯期的
      Oracle JDBC原生類依賴,同時借助Oracle JDBC提供的原生功能完成Clob字段的寫入,該代碼是從Ali Ibrahim,Scott Miller的代碼修改而來,支持Oracle 9以上版本,Oracle 8對應的實現(xiàn)參照
      http://www./56.html網(wǎng)址提供的解決方案。另外此代碼必須運行在最新版的
      Oracle JDBC Driver上。

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多