`
ielts0909
  • 浏览: 11607 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

自己动手模仿Hibernate写数据库框架

阅读更多
自己动手模仿Hibernate写数据库框架

最近项目有点儿停滞,论文看的也比较浮躁,于是就打算重写下后台的框架,数据库部分模仿Hibernate随手写个小程序,当然还没有写完,不过最简单的功能已经能有了,打算把代码贴上来,后续不断的更新。
简单介绍下这个框架:采用DBCP连接池,然后实现了类似Hibernate的按对象插入、更新、删除等。当然还没有写生命周期、延迟加载这些,不过后续会慢慢的加上去,否则就太小儿科了不是么。这个框架是建立在我原有的一个BDUtil的小项目上的,当时做插入这些操作需要传SQL语句和参数,现在把这步也省略了,当然最大的好处就是不用写SQL。
下面就上代码:
Commons.java: DBCP连接池,返回Connection对象。
package org.gfg.dbutil.common;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSourceFactory;

@SuppressWarnings("static-access")
public class Commons {

	private static DataSource dataSource;
	static {
		try {
			Properties prop = new Properties();
			prop.load(Commons.class.getClassLoader().getResourceAsStream(
					"dbcpconfig.properties"));
			BasicDataSourceFactory factory = new BasicDataSourceFactory();
			dataSource = factory.createDataSource(prop);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static Connection getConnection() throws SQLException {
		return dataSource.getConnection();
	}

	public static void close(ResultSet rs, PreparedStatement ps, Connection conn) {
		try {
			if (rs != null) {

				rs.close();
			}
			if (ps != null) {
				ps.close();
			}
			if (conn != null) {
				conn.close();
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
}


DbUtils.java:主要封装了最基本的CRUD操作。注意在query方法的参数中传入了IResultSetHandler,这个接口的主要功能是对返回的结果集做封装。
package org.gfg.dbutil.common;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.gfg.dbutil.handler.BeanHandler;
import org.gfg.dbutil.handler.IResultSetHandler;

public class DbUtils {

	public static void insert(String sql, Object[] params) throws SQLException {// insert
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			conn = Commons.getConnection();
			ps = conn.prepareStatement(sql);

			for (int i = 0; i < params.length; i++) {
				ps.setObject(i + 1, params[i]);
			}
			
			ps.executeUpdate();
		} finally {
			Commons.close(rs, ps, conn);
		}
	}

	public static void update(String sql, Object[] params) throws SQLException {// update
		DbUtils.insert(sql, params);
	}

	public static void delete(String sql, Object[] params) throws SQLException {// delete
		DbUtils.insert(sql, params);
	}

	public static Object query(String sql, Object[] params,
			IResultSetHandler rsh) throws SQLException {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			conn = Commons.getConnection();
			ps = conn.prepareStatement(sql);
			for (int i = 0; i < params.length; i++) {
				ps.setObject(i + 1, params[i]);
			}
			rs = ps.executeQuery();
			return rsh.handler(rs);
		} finally {
			Commons.close(rs, ps, conn);
		}
	}

	public static Object load(String sql, Object[] params,Class<?> clazz) {
		IResultSetHandler rsh=new BeanHandler(clazz);
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			conn = Commons.getConnection();
			ps = conn.prepareStatement(sql);
			for (int i = 0; i < params.length; i++) {
				ps.setObject(i + 1, params[i]);
			}
			rs = ps.executeQuery();
			return rsh.handler(rs);			
		} catch (SQLException e) {
			
			e.printStackTrace();
		} finally {
			Commons.close(rs, ps, conn);
		}
		return null;
	}
}


IResultSetHandler.java:接口,加工ResultSet结果,可以返回Model,List等,这个可以自行扩展。
package org.gfg.dbutil.handler;

import java.sql.ResultSet;

public interface IResultSetHandler {

	public Object handler(ResultSet rs);
	
}


BeanHandler.java:实现了IResultSetHandler接口,主要还是运用了反射。
package org.gfg.dbutil.handler;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;

public class BeanHandler implements IResultSetHandler {

	private Class<?> beanClass;

	public BeanHandler(Class<?> beanClass) {
		this.beanClass = beanClass;
	}

	@Override
	public Object handler(ResultSet rs) {
		try {
			if (!rs.next()) {
				return null;
			}
			// 用于封装数据的bean
			Object bean = beanClass.newInstance();

			ResultSetMetaData meta = rs.getMetaData();
			int columnCount = meta.getColumnCount();
			for (int i = 0; i < columnCount; i++) {
				String columnName = meta.getColumnName(i + 1);
				Object columnValue = rs.getObject(columnName);
				try {
                 //属性修改器
					PropertyDescriptor pd = new PropertyDescriptor(columnName,
							bean.getClass());
					Method method = pd.getWriteMethod();
					method.invoke(bean, columnValue);
				} catch (Exception e) {
					continue;
				}
			}
			return bean;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}


Session.java:取名字所幸和Hibernate一样了,很简单的利用了反正将运行时的状态给拿出来。
package org.gfg.dbutil.session;

import java.lang.reflect.Field;

import org.gfg.dbutil.common.DbUtils;


public class Session {
	
	public void save(Object obj) { //session.save
		
		int term=obj.getClass().getName().lastIndexOf(".")+1;
		StringBuffer sql = new StringBuffer("Insert into "
				+ obj.getClass().getName().substring(term) + " (");
		Field[] fields = obj.getClass().getDeclaredFields();
	
			int size = fields.length;
			Field field = null;
			Object[] params = new Object[size];
			
			try {
			for (int i = 0; i < size - 1; i++) {
				field = fields[i];
				field.setAccessible(true);//运行时 把private 转成 public
				params[i] = field.get(obj);
				sql.append(field.getName() + ",");
			}
			
			fields[size-1].setAccessible(true);
			params[size - 1] = fields[size - 1].get(obj);
			sql.append(fields[size - 1].getName() + ") VALUES (");

			for (int i = 0; i < size - 1; i++) {
				sql.append("? , ");
			}
			sql.append("?) ");
			
			String strSQL = new String(sql);
			DbUtils.insert(strSQL, params);//insert
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println(sql);
		for(Object objValue:params){
			System.out.print("  value:"+objValue);
		}
	}

	
	public void update(Object obj) {
		
		int term=obj.getClass().getName().lastIndexOf(".")+1;
		StringBuffer sql = new StringBuffer("UPDATE "
				+ obj.getClass().getName().substring(term) + " SET ");
		Field[] fields = obj.getClass().getDeclaredFields();
	
			int size = fields.length;
			Field field = null;
			Object[] params = new Object[size+1];
			
			try {
			for (int i = 0; i < size - 1; i++) {
				field = fields[i];
				field.setAccessible(true);//运行时 把private 转成 public
				params[i] = field.get(obj);
				sql.append(field.getName() + "=?,");
			}
			
			fields[size-1].setAccessible(true);
			params[size - 1] = fields[size - 1].get(obj);
			sql.append(fields[size - 1].getName() + "=? WHERE " +fields[0].getName()+"=?");
			params[size]=params[0];
			
			String strSQL = new String(sql);
			DbUtils.update(strSQL, params);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println(sql);
		for(Object objValue:params){
			System.out.print("  value:"+objValue);
		}	
	}
	
	public void delete(Object obj){
		int term=obj.getClass().getName().lastIndexOf(".")+1;
		StringBuffer sql = new StringBuffer("DELETE from  "
				+ obj.getClass().getName().substring(term) + " WHERE ");
		Field[] fields = obj.getClass().getDeclaredFields();
		sql.append(fields[0].getName()+"=?");
		
		
		Object[] params = new Object[1];
		try {
			fields[0].setAccessible(true);
			params[0]=fields[0].get(obj);
			
			String strSQL = new String(sql);
			DbUtils.delete(strSQL, params);
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
					
		System.out.println(sql);
		for(Object objValue:params){
			System.out.print("  value:"+objValue);
		}	
	}
	
	public Object load(Class<?> clazz,Object uuid){
		
		Object obj=null;
		try {
			obj = clazz.newInstance();			
			Field[] fields = obj.getClass().getDeclaredFields();
			Object[] params = new Object[1];
			int term=obj.getClass().getName().lastIndexOf(".")+1;
			StringBuffer sql = new StringBuffer("SELECT * from  "
					+ obj.getClass().getName().substring(term) + " WHERE "+fields[0].getName()+"=?");
			params[0]=uuid;
			
			String strSQL = new String(sql);
			obj=DbUtils.load(strSQL,params,clazz);
			
			System.out.println(sql);
			for(Object objValue:params){
				System.out.print("  value:"+objValue);
			}	
			
		} catch (Exception e) {
			e.printStackTrace();
		}		
		return obj;
	}
}


然后是POJO对象,这里我还没有写映射,所以数据库还得自己建立,当然表名和类名一致,数据库字段名称和类的成员变量名一直。这里有个需要注意:建立POJO对象时,要将成员变量的第一个设置为数据库的索引,例如我这里用了ID做索引。
package org.gfg.dbutil.model;

public class User {
	private int id;
	private  String name;
	private String pass;

	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 String getPass() {
		return pass;
	}

	public void setPass(String pass) {
		this.pass = pass;
	}

}


最后是单元测试类:写个save和load方法的测试,其他的都差不多。
package test;

import org.gfg.dbutil.model.User;
import org.gfg.dbutil.session.Session;

import junit.framework.TestCase;

public class TestSession extends TestCase{
	public void testSessionSave(){
		User user=new User();
		user.setId(0);
		user.setName("Alin");
		user.setPass("123456");
		Session session=new Session();
		session.save(user);
	}
	
	public void testSessionLoad(){
		Session session=new Session();
		session.load(User.class, 1);//Clazz & ID
	}
}


程序暂告一段落了,写这个文章的时候突然想起来,好多模式还没用上去,不过这样的小东西应付应付一般的也够用了,当然还需要完善很多东西,等有空了接着把他写完。最后面会附下载链接,一个DEMO。


以上只是一种思路。个人愚见,谢谢观看。
本文原创,转载请指明出处,谢谢。
  • DButils.zip (654.1 KB)
  • 描述: 程序代码
  • 下载次数: 241
2
2
分享到:
评论
2 楼 ielts0909 2012-05-08  
elf8848 写道
         

 
1 楼 elf8848 2012-05-07  
         

相关推荐

    自己动手写框架(含PPT、UML、文档、依赖包、代码)

    1 ORM框架——模仿Hibernate 2 MVC框架——模仿struts2 3 IOC框架——模仿Spring 4 框架整合及项目实例 使用技术: 开发语言:Java 开发工具:Eclipse,MyEclipse 数据库:MySQL 数据库工具:Navicat 建模工具:...

    使用struts和hibernate写的一个会员注册

    使用struts和hibernate框架编写的一个会员注册,模仿的CSDN注册界面,数据库使用的是MySQL

    自定义查询框架Criteria

    我尝试着模仿hibernate的criteria构建这么一个轻量级查询框架,提供一下特点: 1 可以根据前台传过来的查询数据自动构建查询条件 2 可以生成纯SQl 3 也可以直接使用preparestatement进行查询,返回我们想要的数据。 ...

    ssh项目源码(学习ssh的非常好的实例项目)

    本代码主要功能是模仿QQ和论坛的功能(增/删/改/查/验证),充分运用了struts/hibernate/spring中的大多数知识点,思路非常清晰,目前功能尚未完善,但可供学习ssh框架技术的程序员研究,后继版本我会尽早发出,有什么问题可...

    S2SH框架实例

    既然学会了Strut2的使用,那下一步当然是想把strut2和其他两大框架团聚了。问题在于,网上教程虽然颇多,但是却很少携带集成实例的教程。本文不仅仅带领各位爱好者,初学者搭建好S2SH,同时也把教程产品(包括数据库...

    电子商务网站

    使用hibernate框架开发。提供数据库和原数据。一个模仿shop++开源项目。只提供前台。

    play framework 框架手册 word 版

    用hibernate持久化对象模型 - 69 - 保持模型stateless - 70 - 07.JPA持久化 - 70 - 启动JPA实体管理器 - 70 - 获取JPA实体管理器 - 70 - 事务管理 - 71 - play.db.jpa.Model支持类 - 71 - 为GenreicModel定制id映射 ...

    百度地图毕业设计源码-Tmall_SSH:技术栈Struts2+Hibernate+Spring+Jsp+Tomcat,是JavaWeb入门非

    整套技术来作为解决方案,实现模仿天猫网站的各种业务场景,现在开始使用框架技术,毕竟工作中还是要用框架。 本项目技术相对老旧,现在很少用 Struts2 了,但如果接手老项目的话还是要懂的,学习过程我们也可以认识...

    java从零开始全栈离线教程

    3 后端框架:Hibernate、Struts、SpringBoot,、Mybatis 等等 4 工具知识:MAVEN、Redis、Docker、Git 等等 5 数据库:oracle、mysql 6 实践项目:基于不同框架的完整的模仿天猫整站的项目J2EE、 SSH、SSM、...

    play框架手册

    用hibernate持久化对象模型 - 69 - 保持模型stateless - 70 - 07.JPA持久化 - 70 - 启动JPA实体管理器 - 70 - 获取JPA实体管理器 - 70 - 事务管理 - 71 - play.db.jpa.Model支持类 - 71 - 为GenreicModel定制id映射 ...

    S2SH集成教程

    是想把strut2 和其他两大框架团聚了。问题在于,网上教程虽然颇多,但是却很 少携带集成实例的教程。本文不仅仅带领各位爱好者,初学者搭建好S2SH,同 时也把教程产品(包括数据库脚本)一起提供给大家,以供参考。我...

    JAVA上百实例源码以及开源项目

     通过网络或磁盘等方式,把公钥编码传送给李四,李四接收到张三编码后的公钥,将其解码,李四用张三的公钥加密信息,并发送给李四,张三用自己的私钥解密从李四处收到的信息…… Java利用DES私钥对称加密代码实例 ...

    JAVA上百实例源码以及开源项目源代码

     通过网络或磁盘等方式,把公钥编码传送给李四,李四接收到张三编码后的公钥,将其解码,李四用张三的公钥加密信息,并发送给李四,张三用自己的私钥解密从李四处收到的信息…… Java利用DES私钥对称加密代码实例 ...

    百度地图毕业设计源码-https-github.com-czwbig-Tmall_SSH:https-github.com-czwbig-Tm

    整套技术来作为解决方案,实现模仿天猫网站的各种业务场景,现在开始使用框架技术,毕竟工作中还是要用框架。 本项目技术相对老旧,现在很少用 Struts2 了,但如果接手老项目的话还是要懂的,学习过程我们也可以认识...

    java源码包---java 源码 大量 实例

     通过网络或磁盘等方式,把公钥编码传送给李四,李四接收到张三编码后的公钥,将其解码,李四用张三的公钥加密信息,并发送给李四,张三用自己的私钥解密从李四处收到的信息…… Java利用DES私钥对称加密代码实例 ...

    java源码包2

     通过网络或磁盘等方式,把公钥编码传送给李四,李四接收到张三编码后的公钥,将其解码,李四用张三的公钥加密信息,并发送给李四,张三用自己的私钥解密从李四处收到的信息…… Java利用DES私钥对称加密代码实例 ...

    java源码包3

     通过网络或磁盘等方式,把公钥编码传送给李四,李四接收到张三编码后的公钥,将其解码,李四用张三的公钥加密信息,并发送给李四,张三用自己的私钥解密从李四处收到的信息…… Java利用DES私钥对称加密代码实例 ...

    java源码包4

     通过网络或磁盘等方式,把公钥编码传送给李四,李四接收到张三编码后的公钥,将其解码,李四用张三的公钥加密信息,并发送给李四,张三用自己的私钥解密从李四处收到的信息…… Java利用DES私钥对称加密代码实例 ...

Global site tag (gtag.js) - Google Analytics