第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

首頁(yè) 慕課教程 Hibernate 入門教程 Hibernate 入門教程 Hibernate 自動(dòng)進(jìn)行數(shù)據(jù)封裝

Hibernate 自動(dòng)進(jìn)行數(shù)據(jù)封裝

1. 前言

Hibernate 可以構(gòu)建各種復(fù)雜的 SQL 語(yǔ)句,但其本質(zhì)都是反射機(jī)制結(jié)合映射關(guān)系完成的。

框架也僅是一款程序產(chǎn)品,人為編寫的產(chǎn)物。要相信,只要你愿意,你完全可以實(shí)現(xiàn)自己的 JDBC 框架。

本節(jié)課和大家繼續(xù)聊聊 Hibernate 是如何自動(dòng)封裝數(shù)據(jù)的。

2. 理想狀態(tài)

程序中的數(shù)據(jù)通過(guò) SQL 語(yǔ)句傳遞給數(shù)據(jù)庫(kù),從 IO 流的角度上理解是數(shù)據(jù)的輸出。

把數(shù)據(jù)庫(kù)中的數(shù)據(jù)封裝成程序能識(shí)別、使用的類型,這個(gè)過(guò)程叫數(shù)據(jù)庫(kù)封裝。從 IO 流的角度上講是數(shù)據(jù)的輸入。

數(shù)據(jù)封裝的實(shí)現(xiàn)還是利用反射機(jī)制。

數(shù)據(jù)封裝的思路也簡(jiǎn)單。

表結(jié)構(gòu)對(duì)應(yīng)類結(jié)構(gòu),一行記錄或說(shuō)一個(gè)實(shí)體對(duì)應(yīng)一個(gè)對(duì)象,字段對(duì)應(yīng)屬性。還是同樣的配方。

即將編寫實(shí)例之前,先做一個(gè)理想化的假設(shè):

  • 表名和類名相同;
  • 表中的字段名和類中的屬性名相同;
  • 實(shí)體類中沒(méi)有特別復(fù)雜的數(shù)據(jù)類型。

理想狀態(tài)設(shè)定便于大家由淺入深理解實(shí)現(xiàn)過(guò)程。

真實(shí)項(xiàng)目中,很難達(dá)到理想化狀態(tài) 。因?yàn)?JAVA 程序和關(guān)系型數(shù)據(jù)庫(kù)的命名規(guī)范有差異性,不管誰(shuí)遷就誰(shuí),都會(huì)讓彼此難受。

在上一節(jié)課的自定義 Session 對(duì)象中添加一個(gè)封裝方法:

public class MySession<T> {
public T get(Class<T> clz, Serializable id) throws Exception {
	String sql = createSql_(clz, id);
	// JDBC 常規(guī)操作…… 得到結(jié)果集
	ResultSet rs=this.getRs(sql);
	//數(shù)據(jù)封裝
	T entity= this.wrap(clz, rs);	
	return entity;
}
/**
*構(gòu)建 SQL ,具體代碼參考本系列的《Hibernate 自動(dòng)生成SQL語(yǔ)句》 
*/
private String createSql(Class<T> clz, Serializable id) {
    return null;
}
/**
*得到結(jié)果集,此方法就是常規(guī)的 JDBC 操作
*/
private ResultSet getRs(String sql) {
    return  null;
}
/**
*數(shù)據(jù)封裝
*/
private T  wrap(Class<T> clz,ResultSet rs) throws InstantiationException, IllegalAccessException {
	return null;
}
}

關(guān)注 wrap()方法即可,直接讓代碼說(shuō)話:

private T  wrap(Class<T> clz,ResultSet rs) throws InstantiationException, IllegalAccessException {
	// 通過(guò)反射創(chuàng)建對(duì)象
	T entity = clz.newInstance();
	String attName = null;
	Object value = null;
	// 檢查結(jié)果集中是否存在數(shù)據(jù)
	if (rs.next()) {
		// 屬性信息
		Field[] fields = clz.getDeclaredFields();
		for (Field field : fields) {
			// 表的字段名即類的屬性名
			attName = field.getName();
			// 從結(jié)果集獲取值
			value = rs.getObject(attName);
            //允許直接訪問(wèn)私有屬性
			field.setAccessible(true);
            //數(shù)據(jù)封裝
			field.set(entity, value);
		}
	}
	return entity;
}

上面代碼沒(méi)有進(jìn)行類型轉(zhuǎn)換相關(guān)操作,依靠 JAVA 自動(dòng)類型轉(zhuǎn)換完成,對(duì)于常用的基本類型,不會(huì)出多大問(wèn)題。但對(duì)于較復(fù)雜的數(shù)據(jù)類型,需要編碼進(jìn)行強(qiáng)制類型轉(zhuǎn)換。

下面這 2 行代碼,通過(guò)打破私有屬性的壁壘,直接給屬性賦值。只適合用于驗(yàn)證、測(cè)試環(huán)境下。

field.setAccessible(true);
field.set(entity, value);

測(cè)試一下代碼:

Student stu = new MySession<Student>().get(Student.class, new Integer(1));
System.out.println(stu);

在一切理想的狀態(tài)下,一個(gè)簡(jiǎn)易的 JDBC 框架就開(kāi)始工作了。

雖然它很薄弱,且不堪重負(fù),但是,它是黑暗中的一道光,能指導(dǎo)你認(rèn)識(shí)框架本質(zhì)。

3. 非理想狀態(tài)

再來(lái)一個(gè)非理想狀態(tài)下的實(shí)現(xiàn):

  • 類名與表名不同名;
  • 類中的屬性名與表中的字段名有不同的命名;

整體思想和上面代碼沒(méi)有區(qū)別,通過(guò)屬性名找到字段名,因?yàn)閷傩悦妥侄蚊幌嗤?,所以需要通過(guò)屬性上面的注解信息得到字段名。

讓代碼自己說(shuō)話:

private T wrap_(Class<T> clz, ResultSet rs) throws InstantiationException, IllegalAccessException, SQLException,NoSuchMethodException, SecurityException, IllegalArgumentException,InvocationTargetException {
	// 使用反射創(chuàng)建對(duì)象
	T entity = clz.newInstance();
	// 屬性名
	String attName = null;
	// 列名
	String columnName = null;
	Object value = null;
	Column columnAnnotaiton = null;
	// 檢查結(jié)果集中是否存在數(shù)據(jù)
	if (rs.next()) {
		// 屬性信息
		Field[] fields = clz.getDeclaredFields();
		for (Field field : fields) {
			// 屬性名
			attName = field.getName();
			// 查看屬性上面的注解
			columnAnnotaiton = field.getAnnotation(Column.class);
			if (columnAnnotaiton != null) {
				columnName = columnAnnotaiton.name();
			} else {
				columnName = attName;
			}
			// 從結(jié)果集中獲取值
			value = rs.getObject(columnName);
			// 屬性的 set 方法名
			String setMethodName = "set" + attName.substring(0, 1).toUpperCase() + attName.substring(1);
			// 屬性的 set 方法
			Method setMethod = clz.getDeclaredMethod(setMethodName, new Class[] { field.getType() });
			setMethod.invoke(entity, new Object[] { value });
			}
		}
		return entity;
	}

上面代碼一樣沒(méi)有考慮復(fù)雜類型存在情況。

4. 小結(jié)

本節(jié)課程和大家聊了聊 Hibernate 是如何自動(dòng)實(shí)現(xiàn)數(shù)據(jù)封裝的,從實(shí)現(xiàn)原理上講,還是比較容易理解的。

但是,真實(shí)環(huán)境的需求總是千變?nèi)f化的,理想只存于理想中。

Hibernate 的實(shí)現(xiàn)和我們實(shí)現(xiàn)的最大區(qū)別在于,它總是能適應(yīng)不同的需求,要適應(yīng)不同的需求,無(wú)論是代碼的設(shè)計(jì)還是編碼都會(huì)有難度。

但是,千里之行,始于腳下,一步一步,終能看透所有的本質(zhì)。