`

看我山寨版 hibernate 简单实现 一

阅读更多

      这两天在做山寨的 hibernate,现已完成了 Session save,update, delete, get 还有Query 接口的实现.

Hiberate  ORM是软件在对象与关系数据库之间进行转换的一个模块层, 可简化数据库操作Dao类的实现.

一. 技术要点: 

1. 动态装载

 

      程序运行后才决定要装载哪些类,然后才实例化.

装载

Class c = Class.forName(className);

 

实例化

Object o = c.newInstance(); //调用的只是类的无参构造方法,但对本程序来说已经足够了

 

2 .反射

通过一个类的Class 类对象可以得到此类的所有信息,如 静态块,属性,方法,父类、接口,构造器,异常,方法参数,方法返回值, 它们都以对象的形式出现。一切皆对象。但是private 修饰的属性,方法却得不到,还是得要访问权限的。

java.lang.reflect Method[] m = c.getMethods();//到所有方法

...

得到的方法还可以调用

如 Object rt = m[0].invoke(o,参数);

class User{
   private String name;

   public void getName()
   {
      return name
   }
   public String setName(String name){
      this.name = name;
   }

}

 

如果我们要把从数据库中得到的  "name" 字段值 赋给 User 的name属性该怎么做?

那就应该调用 setName方法了.不会是一般的调用,用反射。

 

3。读取xml配置文件

 

使用dom4j

SAXReader reader = new SAXReader();
Document doc = reader.read(file); // file为File 对象
Element root = doc.getRootElement(); //得到根结点
Element e = root;
Iterator it=e.elementIterator();//得到迭代器

 

4. 得到xml配置文件的路径

这我以前讲过的,在写web工程时 src目录下的文件实际上被放到了 WEB-INF/classes下了

 

		String path = this.getClass.toString();//得到类名
		path = this.getClass.getResource(path.substring(path.lastIndexOf(".")+1)+".class").toString();//得得此类的路径  
		path = path.substring(0,path.indexOf("/WEB-INF"));  //得到项目路径
		path = path + "/WEB-INF/classes";//得到classes路径
		path = path + "/hibernate.hbm.xml";//得到配置文件路径
		if(path.startsWith("jar:")){
			path = path.substring(4);
		}
		URI uri = null;
		try {
			uri = new  URI(path);
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
		Log.printLog("uri="+uri);
		File file = new File(uri);
		if(!file.exists()){
			Log.printLog("配置文件不存在!");
			return null;
		}

 

 

二。 配置及使用

 

1. 在src目录下建立hibernate.hbm.xml,先要引入mysql的驱动包啊

 

<?xml version="1.0" encoding="UTF-8"?>

<hibernate-configuration>
<session-factory>
<property name="show_sql">true</property> //显示sql
<property name="dialect">mysql</property>   //数据库名
<property name="driver">com.mysql.jdbc.Driver</property> //
<property name="url">jdbc:mysql://localhost:3306/catpage</property>
<property name="username">root</property>
<property name="password">root</property>
<mapping-resource>User.hbm.xml</mapping-resource>      //pojo映射文件
</session-factory>
</hibernate-configuration>

 

    这和真的Hernate 差不多

 

2. 再在同级目录下建User.hbm.xml文件,也可以要其他路径,但得修改hibernate.hbm.xml了

<?xml version="1.0" encoding="UTF-8"?>
<hibernate-mapping>
<class name="cn.netjava.model.User" table="user"> //pojo路径及表名
<id name="id" column="id"></id>  //主键

<property name="name" column="name" /> //字段
<property name="pwd"  column="pwd"/>
</class>
</hibernate-mapping>

 

3.编写pojo类 如User

package cn.netjava.model;

public class User {

	private int id;
	private String name;
	private String pwd;
	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 getPwd() {
		return pwd;
	}
	public void setPwd(String pwd) {
		this.pwd = pwd;
	}
}

 

4.开始测试吧

package cn.netjava.model;

import cn.netjava.hibernate.Configuration;
import cn.netjava.hibernate.Session;

public class Test {

	public static void main(String args[]){
		try {
			//
			Session session = new Configuration().configure().buildSessionFactory().openSession();
			User user = (User)session.query(User.class, 8);//取得id为8的user
			System.out.println("name="+user.getName()+"\tpwd="+user.getPwd());
			
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

 

 

打印结果: 

//省略.事先已经有了user表,也可用save方法,就可不事先建表啦

 name=a pwd=a 

 

 

 

三..再看代码吧.

 

首先是Session接口

 

package cn.netjava.hibernate;

public interface Session {

	/**
	 * 保存 pojo到数据库中
	 * @param obj  pojo bean对象
	 * @return  返回主键
	 */
	public int save (Object obj,Class c) ;
	/**
	 * 查询数据库得到pojo对象
	 * @param c pojo的类对象
	 * @param priKey 主键
	 * @return  pojo对象
	 */
	public Object query(Class c,Object priKey);
	
	/**
	 * 更新pojo到数据库中
	 * @param priKey 主键 属性值
	 * @param obj 要更新的pojo对象
	 * @param c 要更新的pojo 类对象
	 */
	public void update(Object priKey,Object obj,Class c);
	
	/**
	 * 从数据库中删除 pojo
	 * @param priKey 主键值
	 *  @c: pojo的类对象
	 *  return 删除是否成功
	 */
	public boolean delete(Object priKey,Class c);
	
	/**
	 * 使用sql查询语句查询
	 * @param sql sql查询语句
	 * @return 查询对象
	 */
	public Query createQuery(String sql);
	
}

 

它的实现类是 HibernateSession, 只看save代码好了

 

	/**
	 * 保存 pojo到数据库中
	 * @param obj  pojo bean对象
	 * @c Pojo的类对象
	 * @return  返回主键
	 */
	public int save (Object obj,Class c) {
		MappingConfiguration mc = findConfig(c);//pojo的配置信息类
//		查询是否有表存在,不存在则创建

		if(!hasTable(mc.getTable())){
			try {
				if(createTable(obj,c,mc.getTable())){
					Log.printLog("已创建表"+mc.getTable());
					tableMap.put(mc.getTable(), true);
				}
				else{
					Log.printLog("创建表失败");
					return 0;
				}
				
			} catch (Exception e) {
				Log.printLog("创建表失败");
				e.printStackTrace();
				return 0;
			}
		}
		
		List<Word> wordList = mc.getWordList(); // 取得pojo的字段列表
		
		//生成sql语句
		String sql = "insert into "+mc.getTable() +"(";
		for(Word w:wordList){
			if(!w.getAttrname().equals(mc.getPriKey().getAttrname())){//不是主建
				sql+=w.getColumn()+",";
			}
		}
		sql+=") values(";
		for(Word w:wordList){
			if(!w.getColumn().equals(mc.getPriKey().getColumn())){
				sql+="?,";
			}
		}
		sql+=")";
		/*  下几行为将sql中()里的多余的','去掉*/
		StringBuffer sb = new StringBuffer(sql);
		int s = sb.indexOf(",)");
		while(s>0){
			sb.deleteCharAt(s);
			s=sb.indexOf(",)");
		}
		sql =sb.toString();
		
		PreparedStatement pstmt = dbconn.getPSatement(sql);
		int num=0;
		try{
			//填充sql中的?
			for(Word w:wordList){
				if(!w.getColumn().equals(mc.getPriKey().getColumn())){
					Method m = Tool.getGetMethod(c,w.getAttrname());
					Object ort = m.invoke(obj);
					System.out.println("ort="+ort);
					pstmt.setString(++num, ort.toString());
						
				}	
			}
			pstmt.execute();
		}
		catch(Exception e){
			e.printStackTrace();
		}
		
		//以下为得到表中最后一行,因为设定mysql的主键生成方式为递增的,才能得到刚插入的行的 id
		sql = "select * from "+mc.getTable()+" order by "+mc.getPriKey().getColumn()+" desc limit 1";
		Query query = createQuery(sql);
		query.addEntity(c);
		List l = query.list();
		Object result = l.get(0);
		Method mPriKey = Tool.getGetMethod(c, mc.getPriKey().getAttrname());//取得主键的get方法
		Object rt = null;
		try {
			rt = mPriKey.invoke(result);
		} catch (Exception e) {
			Log.printLog("取得主键时出错了");
			e.printStackTrace();
		}
		Log.printLog("priKek="+rt);
		return Integer.parseInt(rt.toString());
	}

 

再看Query接口吧,它是查询数据库必要的,它的实现 是QueryImp,不贴出来了

 

package cn.netjava.hibernate;

import java.util.List;
/**
 * 查询接口
 * @author sky
 *
 */
public interface Query {

	/**
	 * 给查询得到的结果加入类型
	 * @param c 要转换成的类的类对象
	 */
	public void addEntity(Class c);
	/**
	 * 执行查询
	 * @return 是否成功
	 */
	public boolean excute();
	/**
	 * 得到查询结果,放到List中
	 * @return 结果列表
	 */
	public List list();
	
	/**
	 * 设置预编译sql
	 * @param index '?'的索引,从1开始
	 * @param value '?'的值
	 */
	public  void setString(int index,String value);
	/**
	 * 设置预编译sql
	 * @param index '?'的索引,从1开始
	 * @param value '?'的值
	 */
	public void setInt(int index,int value);
	/**
	 * 设置预编译sql
	 * @param index '?'的索引,从1开始
	 * @param value '?'的值
	 */
	public void setFloat(int index,float value);
}

 

Configuration配置类

 

/**
 * hibernate 的配置类
 * @author sky
 *
 */
public class Configuration {

	private boolean isShowSql;  				//是否显示sql语句
	private String dialect;						//连结数据库的类型
	private String driver;						//连结数据库的驱动
	private String url;							//连结数据库的url地址
	private String username;					//连结数据库的用户名
	private String password;					//连接数据库的密码
	private List<String> mapping_resource;		//pojo的映射配置文件
	private List<MappingConfiguration> mcList;	//pojo的映射配置信息列表

     /*

      上面所有属性的seter,getter方法都有
       */



	/**
	 * 读取配置文件
	 * @return this
	 */
	public Configuration configure(){
                          /*读xml*/
                          ......
               }

	/**
	 * 建立Session的工厂类
	 * @return 工厂
	 * @throws Exception 
	 */
	public SessionFactory buildSessionFactory() throws Exception{
		SessionFactory sf = SessionFactory.getSessionFactory(this);
		return sf;
	}


}

 

 还待完善

 好了,不宜将所有代码都帖上,有兴趣就下代码看看吧

 

分享到:
评论
1 楼 javafound 2010-11-12  
才看到 ,8错.

相关推荐

Global site tag (gtag.js) - Google Analytics