之前写了Spring的实现原理,今天我们接着聊聊Hibernate的实现原理,这篇文章只是简单的模拟一下Hibernate的原理,主要是模拟了一下Hibernate的Session类。好了,废话不多说,先看看我们的代码:

package com.tgb.hibernate;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.xpath.XPath; import com.tgb.hibernate.model.User; public class Session { //表名
String tableName = "user"; //存放数据库连接配置
private Map<String, String> conConfig = new HashMap<String, String>(); //存放实体属性
private Map<String ,String > columns = new HashMap<String ,String >(); //实体的get方法集合
String methodNames[]; public Session () { //初始化实体,这里就不用读取配置文件的方式了,有点麻烦。
columns.put("id", "id");
columns.put("name", "name");
columns.put("password", "password");
methodNames = new String[columns.size()]; } /**
* 创建数据库连接
* @return
* @throws Exception
*/
public Connection createConnection() throws Exception {
//解析xml文件,读取数据库连接配置
SAXBuilder sb = new SAXBuilder();
Document doc = sb.build(this.getClass().getClassLoader().getResourceAsStream("hibernate.cfg.xml"));
Element root = doc.getRootElement();
List list = XPath.selectNodes(root, "/hibernate-configuration/property"); for (int i = 0; i < list.size(); i++) {
Element property = (Element) list.get(i);
String name = property.getAttributeValue("name");
String value = property.getText();
conConfig.put(name, value);
} //根据配置文件获得数据库连接
Class.forName(conConfig.get("driver"));
Connection con = DriverManager.getConnection(conConfig.get("url"),conConfig.get("username"),conConfig.get("password")); return con;
} /**
* save方法,持久化对象
* @param user
*/
public void save(User user) { String sql = createSql();
System.out.println(sql); try {
Connection con = createConnection();
PreparedStatement state = (PreparedStatement) con.prepareStatement(sql); for(int i=0;i<methodNames.length;i++) { //得到每一个方法的对象
Method method = user.getClass().getMethod(methodNames[i]); //得到他的返回类型
Class cla = method.getReturnType(); //根据返回类型来设置插入数据库中的每个属性值。
if(cla.getName().equals("java.lang.String")) {
String returnValue = (String)method.invoke(user);
state.setString(i+1, returnValue);
}
else if(cla.getName().equals("int")) {
Integer returnValue = (Integer) method.invoke(user);
state.setInt(i+1, returnValue);
}
} state.executeUpdate();
state.close();
con.close(); } catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 得到sql语句
* @return 返回sql语句
*/
private String createSql() { //strColumn代表数据库中表中的属性列。并将其连接起来。
String strColumn = "";
int index=0;
for(String key :columns.keySet())
{
strColumn +=key+",";
String v = columns.get(key); //获得属性的get方法,需要将属性第一个字母大写如:getId()
v = "get" + Character.toUpperCase(v.charAt(0)) + v.substring(1);
methodNames[index] = v;
index++;
}
strColumn = strColumn.substring(0, strColumn.length()-1); //拼接参数占位符,即:(?, ?, ?)
String strValue = "";
for(int i=0;i<columns.size();i++)
strValue +="?,"; strValue = strValue.substring(0,strValue.length()-1); String sql = "insert into " + tableName +"(" + strColumn + ")" + " values (" + strValue + ")";
return sql;
}
}

以上代码主要是完成了Hibernate的save()方法,该类有一个构造方法,一个构建sql语句的方法,一个获得数据库连接的方法。最后通过save()方法结合前面几个方法获得结果,将实体对象持久化到数据库。

基本原理就是:首先,获得数据库连接的基本信息;然后,获得实体的映射信息;接着,也是最关键的步骤,根据前面获得的信息,组装出各种sql语句(本例只有简单的insert),将实体按照不同的要求查找或更新(增、删、改)到数据库。

当然Hibernate的具体实现远没有这么简单,Hibernate中大量运用了cglib的动态代理,其中load()方法就是一个例子。大家都知道,调用load()方法是Hibernate不会向数据库发sql语句,load()方法得到的是目标实体的一个代理类,等到真正用到实体对象的时候才会去数据库查询。这也是Hibernate的一种懒加载的实现方式。

总结一句话,这些框架之所以能够做到灵活,就是因为它们都很好的利用了懒加载机制,在运行期在确定实例化谁,需要谁实例化谁,什么时候需要,什么时候实例化。这样设计出来能不灵活吗?这些思想值得我们好好研究,并运用到我们的设计中去。

菜鸟学SSH(十五)——简单模拟Hibernate实现原理的更多相关文章

  1. 菜鸟学SSH(五)——Struts2上传文件

    上传文件在一个系统当中是一个很常用的功能,也是一个比较重要的功能.今天我们就一起来学习一下Struts2如何上传文件. 今天讲的上传文件的方式有三种: 1,以字节为单位传输文件: 2,Struts2封 ...

  2. 学习笔记:CentOS7学习之十五: RAID磁盘阵列的原理与搭建

    目录 学习笔记:CentOS7学习之十五: RAID磁盘阵列的原理与搭建 14.1 RAID概念 14.1.1 RAID几种常见的类型 14.1.2 RAID-0工作原理 14.1.3 RAID-1工 ...

  3. 菜鸟学SSH(十三)——Spring容器IOC解析及简单实现

    最近一段时间,“容器”两个字一直萦绕在我的耳边,甚至是吃饭.睡觉的时候都在我脑子里蹦来蹦去的.随着这些天一次次的交流.讨论,对于容器的理解也逐渐加深.理论上的东西终归要落实到实践,今天就借助Sprin ...

  4. 简单模拟Hibernate的主要功能实现

    在学习期间接触到Hibernate框架,这是一款非常优秀的O/R映射框架,大大简化了在开发web项目过程中对数据库的操作.这里就简单模拟其底层的实现. /*******代码部分,及其主要注解***** ...

  5. 菜鸟学SSH(三)——Struts2国际化自动检测浏览器语言版

    前几天发了一篇Struts国际化的博客——<菜鸟学习SSH(二)——Struts2国际化手动切换版>,有网友提了一个意见,见下图: 于是就有了下面修改的版本: web.xml <?x ...

  6. java web学习总结(二十二) -------------------简单模拟SpringMVC

    在Spring MVC中,将一个普通的java类标注上Controller注解之后,再将类中的方法使用RequestMapping注解标注,那么这个普通的java类就够处理Web请求,示例代码如下: ...

  7. JavaWeb学习总结(四十九)——简单模拟Sping MVC

    在Spring MVC中,将一个普通的java类标注上Controller注解之后,再将类中的方法使用RequestMapping注解标注,那么这个普通的java类就够处理Web请求,示例代码如下: ...

  8. 菜鸟学SSH(十八)——Hibernate动态模型+JRebel实现动态创建表

    项目用的是SSH基础框架,当中有一些信息非常相似,但又不尽同样.假设每个建一个实体的话,那样实体会太多.假设分组抽象,然后继承,又不是特别有规律.鉴于这样的情况.就打算让用户自己配置要加入的字段,然后 ...

  9. 菜鸟学SSH(十)——Hibernate核心接口

    在使用Hibernate的时候,我们通常都会用的Configuration.SessionFactory.Session.Transaction.Query和Criteria等接口.通过这些接口可以, ...

随机推荐

  1. Memcache和Redis

  2. win32控制台消息机制

    源码: #include<windows.h>HANDLE hInput; /* 获取标准输入设备句柄 */INPUT_RECORD inRec;/* 返回数据记录 */DWORD num ...

  3. tyvj3481 越狱

    描述 监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种.如果相信房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱 输入格式 输入两个整数 ...

  4. NOIP2012 借教室

    描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样.面对海量租借教室的信息,我们自然希望编 ...

  5. PHP: Local 和 Global 作用域

    函数之外声明的变量拥有 Global 作用域,只能在函数以外进行访问. 函数内部声明的变量拥有 LOCAL 作用域,只能在函数内部进行访问. 下面的例子测试了带有局部和全局作用域的变量: 在上例中,有 ...

  6. zoj.3865.Superbot(bfs + 多维dp)

    Superbot Time Limit: 2 Seconds      Memory Limit: 65536 KB Superbot is an interesting game which you ...

  7. Linux解压安装与卸载

    linux tar.gz zip 解压缩 压缩命令 linux下安装软件主要有这么几种: 1.自动安装: yum install package 2.用二进制文件安装:rpm -ivh file.rp ...

  8. ■Ascii逐字解码法注入,mysql5.0一下版本手工注入

    /*By:珍惜少年时*/ 逐字解码法,不一定非要猜字段内容.库名,表名,字段,data,都能猜. 环境过滤了select.union(mysql5.0以下的版本就不支持union所以也可以用此方法), ...

  9. move 和 CopyMemory的区别

    Move(ABuffer,P, Sizeof(ABuffer));   //指针传递            Move(ABuffer^,P^, Sizeof(TArrayByte));   //复制内 ...

  10. 关于 datasnap Stream的英文博客能容

    转载:http://blogs.embarcadero.com/jimtierney/2009/04/06/31461/ DataSnap Server Method Stream Parameter ...