夜譚hibernate的運行原理

作爲一款優秀封裝dao層的框架,被衆多同仁使用,這篇文章再爲學習hibernate的朋友提供一個理解原理的參考。

下面是我模擬hibernate的運行原理寫的一個程序,希望對大家有用!

首先跟大家分享框架結構圖

第一步,創建Execute對象

第二步,創建ConfigManager對象

第三步,創建configFile對象,configFile包含數據庫連接部分和實體類映射文件

第四步,讀取數據庫連接映射文件盒實體類配置文件

第五步,調用Execute對象的get方法

第六步,根據實體映射類構造SQL語句

第七步,設置對象屬性,返回實體對象

 

看完結構圖,由我帶大家瀏覽一下設計流程:

1、首先創建一個Web Project

2、然後需要導入一個解析XML文件的jar包dom4j-1.6.1.jar和java訪問oracle數據庫的jar包classes12.jar

3、需要在src下寫一個名叫Config.dtd文件和Mapping.dtd,這個文件用於規範配置文件

     a、Config.dtd

<!ELEMENT hibernate (session-factory)>
<!ELEMENT session-factory (property*,mapping*)>
<!ELEMENT property (#PCDATA)>
<!ATTLIST property
	name CDATA #REQUIRED>
<!ELEMENT mapping EMPTY>
<!ATTLIST mapping
	resource CDATA #REQUIRED>

     b、Mapping.dtd

<!ELEMENT hibernate-mapping (class)>
<!ELEMENT class (id,property*)>
<!ATTLIST class
	name CDATA #REQUIRED
	table  CDATA #REQUIRED>
<!ELEMENT id EMPTY>
<!ATTLIST id
	name CDATA #REQUIRED
	type CDATA "java.lang.String"
	column CDATA #REQUIRED>
<!ELEMENT property EMPTY>
<!ATTLIST property
	name CDATA #REQUIRED
	type CDATA "java.lang.String"
	column CDATA #REQUIRED>

4、下面就開始寫各個類

     a、實體映射文件MappingFile類和映射屬性Attribute類

package com.huan.frame;

import java.util.*;

public class MappingFile {
	private String name;
	private String className;
	private String tableName;
	private String primary;
	private List<Attribute> attlist = new ArrayList<Attribute>();
	
	public void addAttribute(Attribute att){
		attlist.add(att);
	}
	public List<Attribute> getAttlist() {
		return attlist;
	}

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getClassName() {
		return className;
	}
	public void setClassName(String className) {
		this.className = className;
	}
	public String getTableName() {
		return tableName;
	}
	public void setTableName(String tableName) {
		this.tableName = tableName;
	}
	public String getPrimary() {
		return primary;
	}
	public void setPrimary(String primary) {
		this.primary = primary;
	}
}
package com.huan.frame;

public class Attribute {
	private String name;
	private String type;
	private String column;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	public String getColumn() {
		return column;
	}
	public void setColumn(String column) {
		this.column = column;
	}
}

     b、實例化MappingManager類

package com.huan.frame;

public class MappingManager {
	public static Object createInstance(MappingFile file){
		try {
			return Class.forName(file.getName()).newInstance();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
}

     c、配置文件ConfigFile類

package com.huan.frame;

import java.util.*;

public class ConfigFile {
	private String connectionDriver;
	private String connectionURL;
	private String connectionUser;
	private String connectionPassword;
	private Map<String,MappingFile> mappings = new HashMap<String,MappingFile>();
	
	public void addMapping(MappingFile mf){
		mappings.put(mf.getName(), mf);
	}
	public MappingFile getMapping(String name){
		return mappings.get(name);
	}
	
	public String getConnectionDriver() {
		return connectionDriver;
	}
	public void setConnectionDriver(String connectionDriver) {
		this.connectionDriver = connectionDriver;
	}
	public String getConnectionURL() {
		return connectionURL;
	}
	public void setConnectionURL(String connectionURL) {
		this.connectionURL = connectionURL;
	}
	public String getConnectionUser() {
		return connectionUser;
	}
	public void setConnectionUser(String connectionUser) {
		this.connectionUser = connectionUser;
	}
	public String getConnectionPassword() {
		return connectionPassword;
	}
	public void setConnectionPassword(String connectionPassword) {
		this.connectionPassword = connectionPassword;
	}
}

     d、配置管理ConfigManager類

package com.huan.frame;

import java.io.InputStream;
import java.sql.*;
import java.util.*;

import org.dom4j.*;
import org.dom4j.io.SAXReader;

public class ConfigManager {
	private ConfigFile config;
	
	public ConfigManager(){
		config = new ConfigFile();
		readConfig();
	}
	
	public void readConfig(){
		try {
			InputStream is = getClass().getResourceAsStream("/Config.xml");
			if(is == null) throw new Exception("hibernate:配置文件未找到!");
			Document doc = new SAXReader().read(is);
			Element root = doc.getRootElement();
			Iterator<Element> sessionNode = root.elementIterator("session-factory");
			Element child = sessionNode.next();
			Iterator<Element> propertys = child.elementIterator("property");
			Element node = null;
			while(propertys.hasNext()){
				node = propertys.next();
				if(node.attributeValue("name").trim().equals("connection.driver"))
					config.setConnectionDriver(node.getTextTrim());
				if(node.attributeValue("name").trim().equals("connection.uri"))
					config.setConnectionURL(node.getTextTrim());
				if(node.attributeValue("name").trim().equals("connection.user"))
					config.setConnectionUser(node.getTextTrim());
				if(node.attributeValue("name").trim().equals("connection.password"))
					config.setConnectionPassword(node.getTextTrim());
			}
			Iterator<Element> mappings = child.elementIterator("mapping");
			while(mappings.hasNext()){
				node = mappings.next();
				MappingFile mf = readMapping(node.attributeValue("resource"));
				config.addMapping(mf);
			}
			System.out.println("hibernate:配置文件加載完畢!");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public MappingFile readMapping(String path){
		MappingFile mapping = new MappingFile();
		try {
			if(path == null) throw new Exception("hibernate:映射文件未找到!");
			mapping.setName(path.substring(5,path.lastIndexOf(".")).replaceAll("/", "."));
			System.out.println("hibernate:映射文件名:" + mapping.getName());
			path = path.substring(4);
			System.out.println("hibernate:映射路徑名:" + path);
			Properties properties = new Properties();
			InputStream is = getClass().getResourceAsStream(path);
			if(is == null) throw new Exception("hibernate:映射文件加載失敗!");
			Document doc = new SAXReader().read(is);
			Element root = doc.getRootElement();
			Iterator<Element> sessionNode = root.elementIterator("class");
			Element child = sessionNode.next();
			mapping.setClassName(child.attributeValue("name"));
			mapping.setTableName(child.attributeValue("table"));
			Iterator<Element> ids = child.elementIterator("id");
			Element id = ids.next();
			mapping.setPrimary(id.attributeValue("name"));
			Attribute attId = new Attribute();
			attId.setName(id.attributeValue("name"));
			attId.setType(id.attributeValue("type"));
			attId.setColumn(id.attributeValue("column"));
			mapping.addAttribute(attId);
			Iterator<Element> propertys = child.elementIterator("property");
			Element property = null;
			Attribute att = null;
			System.out.println("hibernate:進入屬性加載循環!");
			while(propertys.hasNext()){
				property = propertys.next();
				att = new Attribute();
				att.setName(property.attributeValue("name"));
				att.setType(property.attributeValue("type"));
				att.setColumn(property.attributeValue("column"));
				mapping.addAttribute(att);
			}
			System.out.println("hibernate:映射文件加載完畢!");
			return mapping;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	public MappingFile getMapping(String name){
		return config.getMapping(name);
	}
	
	public Connection openConnection(){
		Connection conn = null;
		try {
			Class.forName(config.getConnectionDriver());
			conn = DriverManager.getConnection(config.getConnectionURL()
					,config.getConnectionUser(),config.getConnectionPassword());
			return conn;
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	public void closeAll(Connection conn,PreparedStatement pstmt,ResultSet rs){
		try {
			if(rs != null) rs.close();
			if(pstmt != null) pstmt.close();
			if(conn != null) conn.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}

     e、執行Execute類

package com.huan.frame;

import java.lang.reflect.Method;
import java.sql.*;
import java.util.List;

public class Execute {
	private ConfigManager manager = new ConfigManager();
	
	public Object get(Class c,int id){
		String[] str = c.toString().split(" ");
		MappingFile mf = manager.getMapping(str[1]);
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			Class clazz = Class.forName(mf.getName());
			Object obj = MappingManager.createInstance(mf);
			if(obj == null) throw new Exception("hibernate:反射生成對象實例化失敗!");
			conn = manager.openConnection();
			if(conn == null) throw new Exception("hibernate:連接數據庫失敗!");
			String sql = buildSql(mf);
			System.out.println("hibernate:" + sql);
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, id);
			rs = pstmt.executeQuery();
			int size = mf.getAttlist().size();
			String methodName = null;
			String type = null;
			Method[] methods = clazz.getDeclaredMethods();
			while(rs.next()){
				System.out.println("hibernate:讀取數據...");
				for(int i = 0; i < size; i++){
					methodName = buildMethodName(mf.getAttlist().get(i).getName());
					System.out.println("hibernate:方法名:" + methodName);
					for (Method method : methods) {
						System.out.println("hibernate:遍歷方法名..." + method.getName());
						if(methodName.equals(method.getName())){
							type = mf.getAttlist().get(i).getType();
							System.out.println("hibernate:參數類型:" + type);
							if(type.equals("java.lang.Integer")){
								System.out.println("hibernate:" + method.getName() + "賦值");
								method.invoke(obj, rs.getInt(i + 1));
								break;
							}
							if(type.equals("java.lang.String")){
								System.out.println("hibernate:" + method.getName() + "賦值");
								method.invoke(obj, rs.getString(i + 1));
								break;
							}
						}
					}
				}
			}
			return obj;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			manager.closeAll(conn, pstmt, rs);
		}
		return null;
	}
	
	public String buildSql(MappingFile file){
		try {
			if(file == null) throw new Exception("創建SQL語句的MF文件爲空!");
			String sql = "SELECT ";
			List<Attribute> attList = file.getAttlist();
			for(int i = 0; i < attList.size(); i++){
				if(i == 0) sql += attList.get(i).getColumn();
				else sql += "," + attList.get(i).getColumn();
			}
			return sql += " FROM " + file.getTableName() + " WHERE " + file.getPrimary() + " = ?";
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	public String buildMethodName(String attName){
		try {
			if(attName == null || attName.isEmpty()) throw new Exception("創建方法的屬性名爲空!");
			return "set" + attName.substring(0,1).toUpperCase() + attName.substring(1);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
}

5、寫完各個類之後就是打包,右鍵點擊項目export,保存爲JAR file文件即可!

 

瀏覽完設計流程,就讓我們測試一下我們的hibernate框架吧,let's go!

1、創建一個Web Project項目,導入咱們剛剛寫好的包,還要導入dom4j-1.6.1.jar和classes12.jar,別忘了!

2、創建配置文件和實體類和實體映射文件,注意實體類和實體映射文件必須在一個包下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ActionConfig[
<!ELEMENT hibernate (session-factory)>
<!ELEMENT session-factory (property*,mapping*)>
<!ELEMENT property (#PCDATA)>
<!ATTLIST property
	name CDATA #REQUIRED>
<!ELEMENT mapping EMPTY>
<!ATTLIST mapping
	resource CDATA #REQUIRED>
]>

<hibernate>
	<session-factory>
		<property name="connection.driver">oracle.jdbc.driver.OracleDriver</property>
		<property name="connection.uri">jdbc:oracle:thin:@localhost:1521:orcl</property>
		<property name="connection.user">huan</property>
		<property name="connection.password">orcl</property>
		<mapping resource="/src/com/huan/entity/User.xml"/>
	</session-factory>
</hibernate>

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ActionConfig[
<!ELEMENT hibernate-mapping (class)>
<!ELEMENT class (id,property*)>
<!ATTLIST class
	name CDATA #REQUIRED
	table  CDATA #REQUIRED>
<!ELEMENT id EMPTY>
<!ATTLIST id
	name CDATA #REQUIRED
	type CDATA "java.lang.String"
	column CDATA #REQUIRED>
<!ELEMENT property EMPTY>
<!ATTLIST property
	name CDATA #REQUIRED
	type CDATA "java.lang.String"
	column CDATA #REQUIRED>
]>

<hibernate-mapping>
	<class name="com.huan.entity.User" table="users">
		<id name="id" type="java.lang.Integer" column="id"/>
		<property name="name" column="name"/>
		<property name="pwd" column="password"/>
	</class>
</hibernate-mapping>

3、創建執行類Execute對象,調用get方法。之前我寫了一個struts模擬用的是虛擬數據庫,這次我將我的模擬hibernate替換掉虛擬數據庫

package com.huan.test;

import java.util.*;

import com.huan.entity.User;
import com.huan.frame.Execute;

public class UserDaoImp {
	private Execute execute = null;
	
	public User getUserById(int id){
		execute = HibnateUtil.getExecute();
		return (User)execute.get(User.class, id);
	}
}

還是老規則,輸入數據庫裏有的用戶資料進入index.jsp就算成功了!

今天的hibernate運行原理就跟大家探討到這裏,想交流的朋友請留言或私信。

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