hibernate之模擬Hibernate持久化操作


【Hibernate】之模擬Hibernate持久化操作


 使用過Hibernate,大家都知道,由於其面向對象的設計,用起來非常方便,且具有很好的跨數據庫性,那麼Hibernate的底層是怎麼實現的呢?其實也就是將對象模型轉化爲關係模型,最終還是得sql語句來執行。 

 看過Hibernate源碼的同學應該發現, Hibernate底層的核心是代理和反射,那麼由此這樣我們就可以理解爲什麼使用Hibernate在效率上始終是致命的。

 

 Ok,下面是一個簡單的模擬Hibernate-ORMsave()方法,來管中窺豹,略瞭解一下Hibernate的底層實現。其中這裏我主要演示Hibernate是如何使用反射獲取數據,類型等,到這裏不得不提,廣大Java從業者,想在Java技術道路上有所突破,Java的反射機制,是必須掌握的。

 

首先模擬出新建一個Session實體類,模擬一個save()方法

爲了方便,我這邊就不寫配置文件了,如果各位想寫,可以參考Hibernate


Configuration cfg=new Configuration();
cfg.configure();
sessionFactory=cfg.buildSessionFactory();

Hiberane的源碼導進去,自己看一下它如何利用dom4j解析實現的。


首先創建一個實體類:

package csg.hibernate.entity;
/**
 * 
 * @author Caesar.hu
 * @Date	2014-11-28
 * @Time	上午09:32:08
 * @TODO
 */
public class Student {
	private Integer id;
	private String name;
	private Integer age;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	

}


看代碼:然後我們模擬一個Session類,裏面構造一個save()方法,

下面這段代碼,就是核心,每行代碼的註釋已經寫清楚

package csg.hibernate.entity;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.HashMap;
import java.util.Map;

/**
 * 
 * @author Caesar.hu
 * @Date 2014-11-27
 * @Time 下午06:02:05
 * @TODO模擬一個Session
 */
public class Session {
	// 1、寫好一個表名,這個表名,理論上應該在Student.hbm.xml中讀出來,或者是註解JPA映射
	// 我這裏直接寫出來,意思就是說,數據存到數據庫的表對應的就是這個
	String tableName = "_student";
	// 2、爲什麼創建一個String類型的Map?
	// 這個map存放的就是實體的字段屬性和數據庫字段匹配,本身也是配置在文件中
	Map<String, String> cfs = new HashMap<String, String>();
	String[] methodNames;// new一個空集合主要是方便反射使用

	public Session() {
		cfs.put("_id", "id");
		cfs.put("_name", "name");
		cfs.put("_age", "age");
		methodNames = new String[cfs.size()];
	}

	public void save(Student s) throws Exception {
		// 3、創建SQL語句
		String sql = createSQL();
		String url = "jdbc:mysql://localhost/hibernate";
		String username = "root";
		String password = "root";
		Class.forName("com.mysql.jdbc.Driver");
		Connection conn = DriverManager.getConnection(url, username, password);
		PreparedStatement ps = conn.prepareStatement(sql);
		// 9,sql寫好之後,這裏是是不是需要設置?
		// 類似ps.setName(1,s.getId);
		// ps.setInterge(2,s.getAge)
		//怎麼設置?你怎麼知道傳進來的是什麼類型呢?所以這裏最重要的是需要用到反射類型
		for (int i = 0; i < methodNames.length; i++) {
			System.out.println(methodNames[i]);// 首先取到存進到數據中的getAge getInt
			//10、 通過反射機制根據實體的方法反射出實體一系列的方法getAge,getName,getId和返回類型Integer,String,Integer
			Method m = s.getClass().getMethod(methodNames[i]);
			System.out.println(m);
			System.out.println(s.getClass() + "-------" + m + "---------"
					+ m.getName() + "-----" + m.getReturnType());
			//11、獲取數組裏面getAge,getInt,getName 的返回類型
			Class r = m.getReturnType();
			//12、根據返回類型判斷其應該ps.setString,還是ps.setInteger
			if (r.getName().equals("java.lang.String")) {
				//13、invoke是反射裏面的一個方法,其作用是通過類的返回值類型反射出屬性值
				//14、getAge.invoke(s);同樣也可以通過值反射出返回類型
				String returnValue = (String) m.invoke(s);
				System.out.println(returnValue);
				ps.setString(i + 1, returnValue);
			}
			//15、同樣如果判斷是Integer類型,就ps.setInteger
			if (r.getName().equals("java.lang.Integer")) {
				System.out.println(m.invoke(s));
				Integer returnValue = (Integer) m.invoke(s);
				// System.out.println(returnValue);
				ps.setInt(i + 1, returnValue);
			}
		}
		// ps.executeUpdate();
		ps.close();
		conn.close();
	}

	private String createSQL() {
		String str1 = "";
		int index = 0;
		for (String s : cfs.keySet()) {
			// 4、通過Map中的key得到Value
			String v = cfs.get(s);
			// 5、根據get,set方法我們可以知道字段首字母是需要大寫的,
			// 6、這段代碼就是將取出來的value首字母大寫加上get
			v = Character.toUpperCase(v.charAt(0)) + v.substring(1);
			// 7、這樣new出來的空集合裏面就放上了getId,getName,getAge
			methodNames[index] = "get" + v;
			str1 += s + ",";
			index++;
		}
		str1 = str1.substring(0, str1.length() - 1);
		String str2 = "";
		for (int i = 0; i < cfs.size(); i++) {
			str2 += "?,";
		}
		str2 = str2.substring(0, str2.length() - 1);
		String sql = "insert into " + tableName + "(" + str1 + ")" + "values("
				+ str2 + ")";
		// 8、這段sql==
		// insert into _table(id,name,age)values(?,?,?);
		return sql;
	}

}


最後測試代碼:


package JunitTest;

import csg.hibernate.entity.Session;
import csg.hibernate.entity.Student;
/**
 * 
 * @author Caesar.hu
 * @Date	2014-11-28
 * @Time	上午09:32:15
 * @TODO
 */
public class Test {
	public static void main(String[] args) throws Exception{
		Student student=new Student();
		Session s=new Session();
		student.setId(1);
		student.setAge(12);
		student.setName("張三");
		s.save(student);
	}

}


Ok,到這裏,大家應該能明白,爲什麼說HibernateJDBC的封裝?尤其是在考慮web性能的問題上爲什麼Hibernate不能滿足開發需求,反射機制對於Java是多麼重要

其實Hibernate的源碼寫法也莫不於此,只不過其在底層進行大量的封裝,同時爲了性能Hibernate也有采用直接將數據生成二進制流進行操作。對於配置文件大家可以看Hibernate 源碼是如何利用dom4j解析Hibernate.cfg.xml這個文件,寫的尤其經典,Ok

   Java從業者,想在技術上突破,反射機制是必須掌握的!





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