最近重新複習了一下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