最近重新复习了一下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