揭開ORM的神祕面紗

    今天簡單的講講ORM(object relation mapping 對象關係映射)。如果你對hibernate底層對象關係的映射感覺很神奇的你可以看看這篇文章。很多人接觸hibernate的時候都知道這個ORM,也知道是底層對JDBC的一個封裝,並提供了很多的接口供外部使用,使我們在操作數據庫的時候都,感覺就像是在操作對象一樣。ORM的工作正在此。

    那什麼是ORM呢?他又是如何實現的呢?在此我不在去對hibernate對JDBC的封裝以及線程安全做解釋,主要對對象關係的映射做一個簡單的介紹。
 
    Java Reflect這個應該都知道吧。最常見的就是我們加載數據庫驅動時候Class.forname(driver)通過反射機制加載。所謂ORM就是將我們給定的配置通過反射成相應的對象,同時調用對象的get和set方法。
   
    在此我們來簡單的實現註解對實體的標註,來獲取到實體的信息。同時如何使用反射來調用實體的get和set方法。其實只要你懂得這些,基礎的對象關係映射,那麼你就能夠理解了。(爲了講述方便,xml配置版本的就不在此多說,xml版本其實就是對xml的解析而已)
    首先我們來定義三個註解(如有註解不清楚的,可以去百度或Google),@ORM,@Id,@Column具體代碼如下:
 
  1. @Retention(RetentionPolicy.RUNTIME) 
  2. @Target(ElementType.TYPE) 
  3. public @interface ORM { 
  4.     String table() default ""
  5.     boolean showSQL() default false
  6.  
  7. @Retention(RetentionPolicy.RUNTIME) 
  8. @Target(ElementType.FIELD) 
  9. public @interface Id { 
  10.     String name() default ""
  11.  
  12. @Retention(RetentionPolicy.RUNTIME) 
  13. @Target(ElementType.FIELD) 
  14. public @interface Column { 
  15.     String name() default ""
  16.     String type() default ""
  17.     int length() default 1
  18.     boolean isNull() default true

    好了註解定義成功,這些都是我們需要的屬性,我們只需用將這些註解標註在我們的實體中去,實體標註代碼如下:

  1. @ORM(table = "person", showSQL = true
  2. public class Person { 
  3.     @Id 
  4.     private int id; 
  5.  
  6.     @Column 
  7.     private String name; 
  8.  
  9.     public int getId() { 
  10.         return id; 
  11.     } 
  12.  
  13.     public void setId(int id) { 
  14.         this.id = id; 
  15.     } 
  16.  
  17.     public String getName() { 
  18.         return name; 
  19.     } 
  20.  
  21.     public void setName(String name) { 
  22.         this.name = name; 
  23.     } 
  24.  

     準備工作已經OK,接下來纔是最關鍵的,就是如何去獲取到我們標註的信息,如果去調用對應字段的get和set方法。在Hibernate中,我們通常會使用SessionFactory去過去Session,而在此我們不用接口去做這件事情,爲了簡化我們直接使用一個單例類來完成對實體的信息獲取。

  1. public abstract class BaseSession { 
  2. private static ConnectionProvider connectionProvider = ConnectionProvider 
  3.         .instanceConnectionProvider(); 
  4.  
  5. /** 
  6.  * 獲取表信息 
  7.  *  
  8.  * @param obj 
  9.  */ 
  10. private void getTableInfo(Object obj) { 
  11.     Annotation[] annotationClass = obj.getClass().getAnnotations(); 
  12.     // 獲取表名 
  13.     for (Annotation annotation : annotationClass) { 
  14.         if (annotation instanceof ORM) { 
  15.             ORM orm = (ORM) annotation; 
  16.             table = orm.table(); 
  17.             if (table == null || "".equals(table)) { 
  18.                 String className = obj.getClass().getSimpleName() 
  19.                         .toLowerCase(); 
  20.                 table = className; 
  21.             } 
  22.             showSql = orm.showSQL(); 
  23.         } 
  24.     } 
  25.     ...類似的方法去獲取其他的註解... 
  26. // 獲取實體的值 
  27. private String getFieldValue(Object obj, String fieldName) { 
  28.     Method[] methods = obj.getClass().getDeclaredMethods(); 
  29.     String value = ""
  30.     for (Method method : methods) { 
  31.         if (method.getName().contains( 
  32.                 fieldName.substring(1, fieldName.length())) 
  33.                 && (method.getName().startsWith("get")) 
  34.                 || method.getName().startsWith("is")) { 
  35.             Object[] objParams = new Object[0]; 
  36.              
  37.             Object result = method.invoke(obj, objParams); 
  38.             value = result.toString(); 
  39.              
  40.         } 
  41.     } 
  42.     return value; 
  43.  
  44. // 設置數據庫查詢出來的值 
  45. protected <T> Object loadToObject(ResultSet rs, Class<T> clazz) { 
  46.    try { 
  47.         int totalColumn = fields.length; 
  48.         while (rs.next()) { 
  49.             // 把值放到field和values中去 
  50.             for (int i = 0; i < totalColumn; i++) { 
  51.                 values[i] = rs.getString(fields[i]); 
  52.             } 
  53.  
  54.         } 
  55.         // 將值放入到對象中去 
  56.         return buildObject(clazz); 
  57.  
  58.     } catch (SQLException e) { 
  59.         // TODO Auto-generated catch block 
  60.         e.printStackTrace(); 
  61.     } 
  62.  
  63.     return null

     在此,我們通過getFieldValue和loadToObject去調用實體的get和set方法,以使我們在底層將這些對象與關係數據庫之間建立起橋樑。以此讓我們在具體的方法中直接去調用即可。

  1. public class Session extends BaseSession implements SessionFactory { 
  2.      
  3.     /** 
  4.      * 保存對象 
  5.      */ 
  6.     public boolean save(Object obj) { 
  7.         try { 
  8.             conn = super.getConnection(); 
  9.             conn.setAutoCommit(true); 
  10.             String sql = super.buildSQLForSave(obj); 
  11.             PreparedStatement stmt = conn.prepareStatement(sql); 
  12.             boolean success = stmt.execute(); 
  13.             return !success; 
  14.         } catch (SQLException e) { 
  15.             e.printStackTrace(); 
  16.             return false
  17.         } finally { 
  18.             super.closeConnection(conn); 
  19.         } 
  20.     } 
  21.      
  22.     public <T> Object load(Class<T> clazz, Serializable id){ 
  23.         conn = super.getConnection(); 
  24.         String sql = super.buildLoadSQL(clazz, id); 
  25.         ResultSet rs = null
  26.         PreparedStatement stmt; 
  27.         try { 
  28.             stmt = conn.prepareStatement(sql); 
  29.             rs = stmt.executeQuery(); 
  30.             return super.loadToObject(rs, clazz);        
  31.         } catch (SQLException e) { 
  32.             // TODO Auto-generated catch block 
  33.             e.printStackTrace(); 
  34.         } finally { 
  35.             super.closeConnection(conn); 
  36.         } 
  37.          
  38.         return null
  39.     } 

    由以上代碼我們可以繼承BaseSession中的一些方法,來使用繼續對這些零散方法的一個封裝,以使我們在外部調用的時候就只是去調用它的接口方法即可。

  1. public class Test { 
  2.  
  3.     /** 
  4.      * @param args 
  5.      */ 
  6.     public static void main(String[] args) { 
  7.         // TODO Auto-generated method stub 
  8. //      Person person = new Person(); 
  9. //      person.setId(5); 
  10. //      person.setName("Test"); 
  11. //       
  12.         SessionFactory sessionFactory = new Session(); 
  13. //      boolean isSuccess = sessionFactory.save(person); 
  14. //      if(isSuccess){ 
  15. //          System.out.println("保存成功"); 
  16. //      } else { 
  17. //          System.out.println("保存失敗"); 
  18. //      } 
  19.          
  20.         Person person = (Person)sessionFactory.load(Person.class1); 
  21.         System.out.println("===查詢結果==="); 
  22.         System.out.println("Id: " + person.getId()); 
  23.         System.out.println("Name: " + person.getName()); 
  24.          
  25.     } 
  26.  

    至此,ORM的簡單講解就到此,真正的ORM遠比這個複雜的多,這裏只是對他實現的原理簡單的做個總結,以使更多的初學者對hibernate不只是會用,還能清楚他並不是那麼神祕!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章