Hibernate模擬

最近重新複習了一下hibernate,並且看了馬士兵的Hibernate視頻。說真的,跟着馬士兵老師學,真的可以學到很多東西。


想要深入學習Hibernate,模擬一個Hibernate,我覺得是個不錯的選擇,只要我們能從原理上理解Hibernate,我覺得也差不多學會了Hibernate了,剩下的只是學習怎樣用,怎麼用好。


參考了馬老師視頻上的Hibernate模擬,改進了一下,並且做個更深入的模擬。做了一個Hibernate模擬。


Hibernate把面向對象的Java語言和非面向對象的SQL連接了起來,大大減少了Java程序中JDBC語句的編寫,Hibernate編寫的初衷,我覺得應該是解決面嚮對象語言與關係型數據庫不平衡的問題。


從Hibernate的文件結構,我們可以看到很多東西:

1,hibernate.cfg.xml:這是一個配置數據庫連接的配置文件。如果在普通的JDBC中編寫,需要編寫連接語句,如果複雜一點可能需要編寫連接池,當然現在已經有很多連接池的實現了,如Tomcat的連接池。而如果是Hibernate,則是直接配置就OK,

2,xxx.hbm.xml:一開始學習,我不瞭解hbm是什麼意思,後來就瞭解了,就是“hibernate mapping”,其實就是一個映射文件,把Java實體類的屬性與數據庫表的屬性映射起來。從而實現控制Java的實體類,就可以控制數據庫。

3,剩下的就是hibernate的核心類了,使用這些核心類,可以操作Java對象,從而操作數據庫。


既然是這樣,那我們就模擬上面的功能,做一個Hibernate的模擬:

1,hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<hibernate-configuration>
    <session-factory>
        <property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
        <property name="connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property>
        <property name="connection.username">xxxx</property>
        <property name="connection.password">xxxx</property>
        <property name="dialect">org.hibernate.dialect.OracleDialect</property>
    </session-factory>
</hibernate-configuration>

這裏的語法是借鑑的hibernate.cfg.xml的,去掉了DOCTYPE,這個文件保存的是數據庫連接的信息。

2,實體

我們先在oracle建立一個表和對應的序列:

CREATE TABLE person(
  c_id INT PRIMARY KEY ,
  c_name VARCHAR2(20) ,
  c_age INT
) ;

CREATE SEQUENCE person_sequence  
INCREMENT BY 1   -- 每次加幾個  
START WITH 1     -- 從1開始計數  
NOMAXVALUE       -- 不設置最大值  
NOCYCLE          -- 一直累加,不循環  
CACHE 10; 

編寫實體類:

package org.jian.hibernate;

public class Person {
	private int id;
	private String name;
	private int age;

	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;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

}

編寫實體類與數據表的映射文件

Person.hbm.xml:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping>
	<class name="org.jian.Person" table="Person">
		<id name="id" type="java.lang.Integer">
			<column name="c_id"></column>
			<generator class="sequence">
				<param name="sequence">person_sequence</param>
			</generator>
		</id>
		<property name="name" type="java.lang.String">
			<column name="c_name" length="1212"></column>
		</property>
		<property name="age" type="java.lang.Integer">
			<column name="c_age"  length="1212"></column>
		</property>
	</class>
</hibernate-mapping>

這個文件借鑑hibernte的實體配置文件


3,爲了模擬Hibernate,我們先寫一個測試類Main:

package org.jian.hibernate;

public class Main {
	public static void main(String[] args) {
		Person person = new Person();
		person.setName("混沌");    //對象添加屬性
		person.setAge(10000);
		
		//模擬期中一部分
		//Configuration的主要作用是讀取hibernate.cfg.xml
		//並連接數據
		Configuration cfg = new Configuration().configure();   
		
		//然後我們通過配置文件直接打開一個session
		//省略了hibernate中需要使用SessionFactory
		Session session = cfg.openSession() ;
		session.save(person);
	}
}

4,編寫Configuration類文件:

package org.jian.hibernate;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.PrePersist;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class Configuration {
	private String driver_class;   //數據庫驅動
	//數據庫連接需要的url ,username, password
	private String url;           
	private String username;
	private String password;

	public String getDriver_class() {
		return driver_class;
	}

	public void setDriver_class(String driver_class) {
		this.driver_class = driver_class;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	
	/**
	 * 通過Dom解析xml獲取hibernte.cfg.xml的信息
	 * @return
	 */
	public Map<String, String> getMap() {
		Map<String, String> map = new HashMap<String, String>(); 
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = null;
		Document doc = null;
		try {
			builder = dbf.newDocumentBuilder();
			doc = builder.parse("src/org/jian/hibernate.cfg.xml"); 
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		Element root = doc.getDocumentElement(); 
		NodeList rootList = root.getElementsByTagName("property");
		for (int i = 0; i < rootList.getLength(); i++) {
			Element element = (Element) rootList.item(i);
			Node n = element.getFirstChild();

			String name = element.getAttribute("name");
			String value = n.getNodeValue();

			map.put(name, value);
		}

		return map;
	}

	/**
	 * 獲取的連接信息,但還沒連接數據庫
	 * @return
	 */
	public Configuration configure() {
		
		Map<String, String> map = getMap();

		String driver_class = map.get("connection.driver_class");
		String url = map.get("connection.url");
		String username = map.get("connection.username");
		String password = map.get("connection.password");

        setDriver_class(driver_class);
        setUrl(url);
        setPassword(password);
        setUsername(username);
		return this;
	}

	
	/**
	 * 連接數據庫
	 * 併產生session對象
	 * @return
	 */
	public Session openSession() {
		Connection conn = ConnectionUtil.getConnection(username, password, url, driver_class) ;
	    if (conn!=null) {
			System.out.println("數據庫連接成功");
		}
		return new Session(conn);
	}

}

數據庫連接類:

package org.jian.hibernate;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;


//連接數據庫的util類
public class ConnectionUtil {
	public static Connection getConnection(String username, String password, // 連接數據庫的方法
			String url, String driver) {
		Connection conn = null;
		try {
			Class.forName(driver);
			conn = DriverManager.getConnection(url, username, password);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return conn;
	}

	public static void closeAll(Connection conn, Statement stat, ResultSet rs) { // 關閉數據庫資源
		try {
			if (null != conn) {
				conn.close();
				conn = null;
			}
			if (null != stat) {
				stat.close();
				stat = null;
			}
			if (null != rs) {
				rs.close();
				rs = null;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
}

ConnectionUtil類在上篇博客寫到過。


5,編寫實體映射類了,主要是把Person.hbm.xml的映射信息保存起來:

Properyt類:保存hbm.xml中Property節點的屬性信息:

package org.jian.hibernate;

/**
 *保存Person.hbm.xml中property屬性的信息
 */
public class Property {
	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;
	}

}

ID節點的屬性信息:

package org.jian.hibernate;

public class Id extends Property {
    private String generator ;

	public String getGenerator() {
		return generator;
	}

	public void setGenerator(String generator) {
		this.generator = generator;
	}
    
    
}

用一個Mapping類把xml信息讀出來:

package org.jian.hibernate;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class Mapper {
	/**
	 * 用DOM把hbm.xml的屬性讀出來,並保存在List裏
	 */
	public List getMapper() {
		List list = new ArrayList() ;
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = null;
		Document doc = null;
		try {
			builder = dbf.newDocumentBuilder();
			doc = builder.parse("src/org/jian/hibernate/Person.hbm.xml"); // 解析xml文件
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
		Element root = doc.getDocumentElement(); 
		
		NodeList className = root.getElementsByTagName("class");
		for (int k = 0; k < className.getLength(); k++) {
			Property pclass = new Property() ;
			Element classNode = (Element)className.item(k) ;
			NodeList id = classNode.getElementsByTagName("id");
			String table = classNode.getAttribute("table") ;
			String classname = classNode.getAttribute("name") ;
			
			pclass.setName(classname);
			pclass.setColumn(table);
			list.add(pclass) ;
			
			for (int i = 0; i < id.getLength(); i++) {
				Id d = new Id() ;
				Element element = (Element) id.item(i);
				String name = element.getAttribute("name");
				String type = element.getAttribute("type");
				
				d.setName(name);
				d.setType(type);
				
				NodeList column = element.getElementsByTagName("column");
				for (int j = 0; j < column.getLength(); j++) {
					Element e = (Element) column.item(j);
					String _name = e.getAttribute("name");
					d.setColumn(_name);
				}
				
				NodeList generator = element.getElementsByTagName("param");
				for (int j = 0; j < generator.getLength(); j++) {
					Element e = (Element) generator.item(j);
				    String param = e.getFirstChild().getNodeValue() ;
				    d.setGenerator(param);
				}
				list.add(d) ;

			}
			
			//獲取property節點下的各種屬性
			NodeList property = classNode.getElementsByTagName("property"); 
			for (int i = 0; i < property.getLength(); i++) {
				Property p = new Property() ;
				
				Element element = (Element) property.item(i);  //通過property獲取到property屬性的值
				String name = element.getAttribute("name");
				String type = element.getAttribute("type");
				p.setName(name);
				p.setType(type);
				
				
				NodeList column = element.getElementsByTagName("column");
				for (int j = 0; j < column.getLength(); j++) {
					Element e = (Element) column.item(j);
					String _name = e.getAttribute("name");
					p.setColumn(_name);

				}
				
	            list.add(p) ;
			}
		}
		

		return list;
	}
}

session模擬類:

package org.jian.hibernate;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class Session {
	private String oracle_sequence = "";
	private String className = "";
	private String tableName = "";
	private Map<String, String> map = new LinkedHashMap<String, String>();
	private String methodName[];
	private Connection conn = null;
	private PreparedStatement prep = null;

	public Session(Connection conn) {
		this.conn = conn;
		Mapper mapper = new Mapper();
		List list = mapper.getMapper();

		Property classproperty = (Property) list.get(0);
		className = classproperty.getName();
		tableName = classproperty.getColumn();

		Id id = (Id) list.get(1);

		map.put(id.getColumn(), id.getName()); // 保存id的信息
		oracle_sequence = id.getGenerator(); // id的增長類型,由於我們使用oracle數據庫,所以我們採取序列進行自我遞增

		for (int i = 2; i < list.size(); i++) {
			Property property = (Property) list.get(i);
			map.put(property.getColumn(), property.getName());// 把xml文件裏數據庫與類屬性的映射保存在map裏
		}

		methodName = new String[map.size()-1];
		System.out.println(map.toString());
		System.out.println("輸出SQL語句:"+createSQL());
		System.out.println(Arrays.toString(methodName));
	}

	
	/**
	 * 保存對象
	 * @param obj
	 */
	public void save(Object obj) {
		String sql = createSQL();
		PreparedStatement prep = null;
		try {
			prep = conn.prepareStatement(sql);
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
		
		
		for (int i = 0; i < methodName.length; i++) {
			try {
				//通過反射,獲取對應實體類的類型信息
				
				Method m = obj.getClass().getMethod(methodName[i]);    
				Class c = m.getReturnType();
				
				
				//根據對象屬性的類型信息不同,選擇不同的字段插入方式
				if (c.getName().equals("java.lang.String")) {
					String returnType = (String) m.invoke(obj);
					prep.setString(i + 1, returnType);
					System.out.println((i+1)+"+++"+returnType);
					
				} else if (c.getName().equals("int")) {
					Integer returnType = (Integer) m.invoke(obj);
					prep.setInt(i + 1, returnType);
					System.out.println((i+1)+"----"+returnType);
				}
				
				
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			} catch (SecurityException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			
		}
		try {
			prep.executeQuery() ;
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	
	/**
	 * 通過拼SQL語句把map保存的信息拼成sql
	 */
	private String createSQL() {
		String str1 = "";
		String str2 = "";
		int index = 0;

		for (String str : map.keySet()) {
			str1 += str + ",";
			String temp = map.get(str);
			if (index > 0) {
				methodName[index-1] = "get"
						+ Character.toUpperCase(temp.charAt(0))
						+ temp.substring(1);
			}
			index++;
		}

		str2 += oracle_sequence + ".nextval,";
		for (int i = 1; i < map.size(); i++) {
			str2 += "?,";
		}
		str1 = str1.substring(0, str1.length() - 1);
		str2 = str2.substring(0, str2.length() - 1);
		String sql = "INSERT INTO " + tableName + " (" + str1 + ") "
				+ "VALUES (" + str2 + ")";

		return sql;
	}
}

運行Main.java,結果:


Oracle數據庫:


到此,Hibernate的模擬已經完成。

源碼:http://download.csdn.net/detail/u012356022/7597169


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