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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值