今天简单的讲讲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不只是会用,还能清楚他并不是那么神秘!