今天簡單的講講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具體代碼如下:
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.TYPE)
- public @interface ORM {
- String table() default "";
- boolean showSQL() default false;
- }
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.FIELD)
- public @interface Id {
- String name() default "";
- }
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.FIELD)
- public @interface Column {
- String name() default "";
- String type() default "";
- int length() default 1;
- boolean isNull() default true;
- }
好了註解定義成功,這些都是我們需要的屬性,我們只需用將這些註解標註在我們的實體中去,實體標註代碼如下:
- @ORM(table = "person", showSQL = true)
- public class Person {
- @Id
- private int id;
- @Column
- private String name;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
準備工作已經OK,接下來纔是最關鍵的,就是如何去獲取到我們標註的信息,如果去調用對應字段的get和set方法。在Hibernate中,我們通常會使用SessionFactory去過去Session,而在此我們不用接口去做這件事情,爲了簡化我們直接使用一個單例類來完成對實體的信息獲取。
- public abstract class BaseSession {
- private static ConnectionProvider connectionProvider = ConnectionProvider
- .instanceConnectionProvider();
- /**
- * 獲取表信息
- *
- * @param obj
- */
- private void getTableInfo(Object obj) {
- Annotation[] annotationClass = obj.getClass().getAnnotations();
- // 獲取表名
- for (Annotation annotation : annotationClass) {
- if (annotation instanceof ORM) {
- ORM orm = (ORM) annotation;
- table = orm.table();
- if (table == null || "".equals(table)) {
- String className = obj.getClass().getSimpleName()
- .toLowerCase();
- table = className;
- }
- showSql = orm.showSQL();
- }
- }
- ...類似的方法去獲取其他的註解...
- }
- // 獲取實體的值
- private String getFieldValue(Object obj, String fieldName) {
- Method[] methods = obj.getClass().getDeclaredMethods();
- String value = "";
- for (Method method : methods) {
- if (method.getName().contains(
- fieldName.substring(1, fieldName.length()))
- && (method.getName().startsWith("get"))
- || method.getName().startsWith("is")) {
- Object[] objParams = new Object[0];
- Object result = method.invoke(obj, objParams);
- value = result.toString();
- }
- }
- return value;
- }
- // 設置數據庫查詢出來的值
- protected <T> Object loadToObject(ResultSet rs, Class<T> clazz) {
- try {
- int totalColumn = fields.length;
- while (rs.next()) {
- // 把值放到field和values中去
- for (int i = 0; i < totalColumn; i++) {
- values[i] = rs.getString(fields[i]);
- }
- }
- // 將值放入到對象中去
- return buildObject(clazz);
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return null;
- }
在此,我們通過getFieldValue和loadToObject去調用實體的get和set方法,以使我們在底層將這些對象與關係數據庫之間建立起橋樑。以此讓我們在具體的方法中直接去調用即可。
- public class Session extends BaseSession implements SessionFactory {
- /**
- * 保存對象
- */
- public boolean save(Object obj) {
- try {
- conn = super.getConnection();
- conn.setAutoCommit(true);
- String sql = super.buildSQLForSave(obj);
- PreparedStatement stmt = conn.prepareStatement(sql);
- boolean success = stmt.execute();
- return !success;
- } catch (SQLException e) {
- e.printStackTrace();
- return false;
- } finally {
- super.closeConnection(conn);
- }
- }
- public <T> Object load(Class<T> clazz, Serializable id){
- conn = super.getConnection();
- String sql = super.buildLoadSQL(clazz, id);
- ResultSet rs = null;
- PreparedStatement stmt;
- try {
- stmt = conn.prepareStatement(sql);
- rs = stmt.executeQuery();
- return super.loadToObject(rs, clazz);
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } finally {
- super.closeConnection(conn);
- }
- return null;
- }
- }
由以上代碼我們可以繼承BaseSession中的一些方法,來使用繼續對這些零散方法的一個封裝,以使我們在外部調用的時候就只是去調用它的接口方法即可。
- public class Test {
- /**
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- // Person person = new Person();
- // person.setId(5);
- // person.setName("Test");
- //
- SessionFactory sessionFactory = new Session();
- // boolean isSuccess = sessionFactory.save(person);
- // if(isSuccess){
- // System.out.println("保存成功");
- // } else {
- // System.out.println("保存失敗");
- // }
- Person person = (Person)sessionFactory.load(Person.class, 1);
- System.out.println("===查詢結果===");
- System.out.println("Id: " + person.getId());
- System.out.println("Name: " + person.getName());
- }
- }
至此,ORM的簡單講解就到此,真正的ORM遠比這個複雜的多,這裏只是對他實現的原理簡單的做個總結,以使更多的初學者對hibernate不只是會用,還能清楚他並不是那麼神祕!