`

用反射注解实现的ORM(一看就明白的那种)

    博客分类:
  • java
阅读更多

之所以会写这个程序完全是因为偷懒^^,那时在公司实习要我们用jdbc来写练习,想想已经很久没用过纯的jdbc来写操作数据库了,用Hibernate多好啊,最少也可以用ibatis,想到那么SQL语句就烦,写来写去都是那几句。那时刚好学过反射和注解所以就决定自己写一个ORM框架,当然只是简单的那种,刚开始用到了apache下的开源项目dbutils,不过后来就慢慢的改进用反射来代替,虽然现在那用到这个包,关键部分还是用反射实现的.

 

核心类:

 

package com.permission.utils.db;
import java.lang.reflect.Field;
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.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import com.permission.utils.log.LogUtil;




/**
 * @Title: OperateDB.java
 * @Package com.cai.order.db
 * @Description: TODO(ORM)
 * @author awfhome@163.com
 * @date 2010-3-6 下午01:46:05
 * @version V1.2
 */
public class OperateDB {
	
	private Connection conn = null;
	private String sql ="";
	private PreparedStatement pst;
	private Hashtable map = null;
	
	
	
	public void setConnection(Connection conn) {
		this.conn = conn;
	}


	/**
	 * 创建sql语句
	 */
	public void createQuery(String sql){
		map = new Hashtable(); //初始化
		this.sql = sql;	
	}
	
	
	/**设置参数*/
	@Deprecated
	public void setParameter(String name,String val){
		map.put(name, val);
	}
		
	/**设置String类型参数*/
	public void setParameterString(String name,String val){
		map.put(name, val);
	}
	/**设置Integer类型参数*/
	public void setParameterString(String name,Integer val){
		map.put(name, Integer.toString(val));
	}
	/**设置Double类型参数*/
	public void setParameterString(String name,Double val){
		map.put(name, Double.toString(val));
	}
	
	
	
	

	/**
	 * 处理sql语句(数据库标准的sql)
	 */
	private String doSql(){
		
		if(sql!=null && !"".equals(sql)){
			String tem = "";
			Enumeration e = map.keys();
			while(e.hasMoreElements()){
				tem = (String)e.nextElement();
				this.sql = sql.replace(":" + tem, "'" +(String) map.get(tem)+"'");
			}
		}else {
			System.out.println("没有sql语句");
		}
		LogUtil.info("这次调用的sql语名: " + sql);
		return sql;
	}
	
	

	
	
	/**
	 * 返回类数组,这部分用的是dbutils
	 */
	public List list(Class type) throws SQLException{
		doSql(); //调用处理sql成标准
		List list = null;
		QueryRunner queryR = new QueryRunner();
		list = (List)queryR.query(conn, sql,  new BeanListHandler(type));
		return list;
	}
	
	
	/**
	 * 返回单个数据
	 */
	public Object uniqueResult(Class type) throws SQLException{
		doSql();
		Object object = null;
		List list = null;
		QueryRunner queryR = new QueryRunner();
		list = (List)queryR.query(conn, sql,  new BeanListHandler(type));
		if(list != null && list.size()!=0) object = (Object)list.get(0);
		return object;
	}
	
	
	/**
	 * 返回影响行数
	 */
	public int executeUpdate() throws SQLException{
		doSql();
		QueryRunner queryR = new QueryRunner();
		int a = queryR.update(conn,sql);
		return a;
	}
	
	
	
	/** 添加数据
	 * @throws NoSuchMethodException 
	 * @throws SecurityException 
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 * @throws SQLException */
	public int save(Object object) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SQLException {
		
		List<String> list = new ArrayList();
		StringBuffer str = new StringBuffer();
		String _tableName = "";
		
		Class c = object.getClass();
		
		//解析类获取表名
		FieldAnnotation _file = (FieldAnnotation) c.getAnnotation(FieldAnnotation.class);
	
		
		if(_file!=null){
			
			 _tableName = _file.name();//得到表名,如果没有写,将用和类名一样的表名
			if("_null".equals(_tableName)){
				_tableName = c.getSimpleName();
				LogUtil.info("警告:你这个使用的是同类名相同的表名,请在对应的类注解表名! " );
			}
			
		}else {//没有在类上注解表名
			_tableName = c.getSimpleName();
			LogUtil.info("警告:你这个使用的是同类名相同的表名,请在对应的类注解表名! " );
			
		}
		
		str.append("insert into " + _tableName +"(");
		
		
		
		
		
		//解析属性
		Field[] fs = c.getDeclaredFields();			
		for(int i = 0; i < fs.length; i++){
			Field f = fs[i];
			PrimaryAnnotation pa = f.getAnnotation(PrimaryAnnotation.class);
			
			if(pa!=null){
				LogUtil.debug("检测到主键标识,SQL语句忽略主键,对应的字段为:" + f.getName());
			}else { //非主键,忽略主键字键来创建SQL语句
				str.append(f.getName());
				if(i!=fs.length-1) str.append(",");
				list.add(f.getName());
			}
		
		}
		
		
		str.append(") values(");
	//	System.out.println(str);
		
		//解析方法,调用方法get()
		for(int i = 0; i < list.size(); i++){
			String s = list.get(i);
			String tem = s.substring(0, 1).toUpperCase();
			String tem2 = s.substring(1);
			String tem3 = tem + tem2;
			Method m = c.getMethod("get"+ tem3);		
			//System.out.println(m.toString());
			Object result = m.invoke(object);
			if(result==null){
				str.append("null");
			}else{
				str.append("'" +result.toString() + "'");
			}
			
			if(i!=list.size()-1){
				str.append(",");
				String ss = str.toString();
				//System.out.println(ss);
			}	
		}
		
		str.append(")");
		
		sql = str.toString();
		LogUtil.info("此次调用的SQL语名: " + sql);
		QueryRunner queryR = new QueryRunner();
		int a = queryR.update(conn,sql);
		LogUtil.info("添加数据完成!");		
		return a;
	}
	
	
	
	/**根据对象主键修改数据
	 * @throws NoSuchMethodException 
	 * @throws SecurityException 
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 * @throws SQLException */
	public boolean update(Object object) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SQLException{
		List<String> list = new ArrayList();
		StringBuffer str = new StringBuffer();
		String _tableName = "";//表名
		String pk_name = "主键名"; //主键 
		String pk_id = "主键值"; //主键 
		
		Class c = object.getClass();
		//解析类获取表名
		FieldAnnotation _file = (FieldAnnotation) c.getAnnotation(FieldAnnotation.class);
		if(_file!=null){	
			 _tableName = _file.name();//得到表名,如果没有写,将用和类名一样的表名
			if("_null".equals(_tableName)){
				_tableName = c.getSimpleName();
				LogUtil.info("警告:你这个使用的是同类名相同的表名,请在对应的类注解表名! " );
			}
			
		}else {//没有在类上注解表名
			_tableName = c.getSimpleName();
			LogUtil.info("警告:你这个使用的是同类名相同的表名,请在对应的类注解表名! " );
			
		}
		
		//update student set sex='xx',dsf='' where xh=001;
		
		
		str.append("update " + _tableName +" set ");
		//解析属性+方法
		Field[] fs = c.getDeclaredFields();			
		for(int i = 0; i < fs.length; i++){
			Field f = fs[i];
			PrimaryAnnotation pa = f.getAnnotation(PrimaryAnnotation.class);
			
			if(pa!=null){	
				LogUtil.info("检测到主键标识,SQL语句主键,进行主键条件查询");
				pk_name = f.getName();
				
				String tem = pk_name.substring(0, 1).toUpperCase();
				String tem2 = pk_name.substring(1);
				String tem3 = tem + tem2;
				Method m = c.getMethod("get"+ tem3);		
				Object result = m.invoke(object);
				pk_id = result.toString();
				//LogUtil.info("检测到主键标识,SQL语句主键进行条件查询  " + pk_id);
			}else { //非主键,忽略主键字键来创建SQL语句
				String s = f.getName();
				str.append(s);
				str.append("=");
				//调用对应的get方法
				String tem = s.substring(0, 1).toUpperCase();
				String tem2 = s.substring(1);
				String tem3 = tem + tem2;
				Method m = c.getMethod("get"+ tem3);		
				//System.out.println(m.toString());
				Object result = m.invoke(object);
				if(result==null){
					str.append("null");
				}else{
					str.append("'" +result.toString() + "'");
				}
				
				if(i!=fs.length-1) str.append(", ");
			}
		}
		
		str.append(" where " + pk_name + " = " + pk_id );
		
		
		
		sql = str.toString();
		LogUtil.info("此次调用的SQL语名: " + sql);
		QueryRunner queryR = new QueryRunner();
		int a = queryR.update(conn,sql);
		LogUtil.info("添加数据完成!");		
		
		if(a!=0){
			return true;
		}
		return false;
	}
	
	
	
	/**关闭连接*/
	public void close(){
		
		try{
			if (conn != null) {
				conn.close();
			}
		}catch(Exception e){
			LogUtil.info("关闭数据库时出错了...");
			e.printStackTrace();
		}
	}
	

}

 

改进了处理sql语句:

 

public class StringToHql {
	
	private String hql ="";
	private Hashtable map = null;
	
	
	

	//初始化1
	public StringToHql(){
		
	}
	
	//初始化2
	public StringToHql(String hql){
		map = new Hashtable(); //初始化
		this.hql = hql;	
	}
	
	
	/**
	 * 创建hql语句
	 */
	public StringToHql createQuery(String hql){
		map = new Hashtable(); //初始化
		this.hql = hql;	
		return this;
	}
	
	
	/**设置String类型参数*/
	public StringToHql setParameterString(String name,String val){
		map.put(name, val);
		return this;
	}
	/**设置Integer类型参数*/
	public StringToHql setParameterString(String name,Integer val){
		map.put(name, val);
		return this;
	}
	/**设置Double类型参数*/
	public StringToHql setParameterString(String name,Double val){
		map.put(name,val);
		return this;
	}
	
	
	
	/**
	 * 处理hql语句(数据库标准的hql)
	 */
	public String doHql(){
		
		if(hql!=null && !"".equals(hql)){
			String tem = "";
			Enumeration e = map.keys();
			while(e.hasMoreElements()){
				tem = (String)e.nextElement(); //key ~ String
				if(map.get(tem)  instanceof Integer) {
					this.hql = hql.replace(":" + tem, "" +(Integer) map.get(tem)+" ");
				}else if(map.get(tem)  instanceof String){
					this.hql = hql.replace(":" + tem, "'" +(String) map.get(tem)+"'");
				}else if(map.get(tem) instanceof Double){
					this.hql = hql.replace(":" + tem, "" +(Double) map.get(tem)+" ");
				}
				
				
			}
		}else {
			System.out.println("没有sql语句");
		}
		LogUtil.info("这次调用的sql语名[StringToHql]: " + hql);
		return hql;
	}
	
	
	
	
	/**
	 * 测试,使用方法
	 */
	@Test
	public void test1(){
		StringToHql st = new StringToHql();
		st.createQuery("from Manager where anutoh=:anutoh");
		st.setParameterString("anutoh", "小明");
		String hql =  st.doHql();
		
		System.out.println(hql);
		
	}
	
	@Test
	public void test2(){
		String hql =  new StringToHql("from Manager where anutoh=:anutoh and  mone=:mone")
							.setParameterString("anutoh", "小明2")
							.setParameterString("mone", 4500.5)
							.doHql();
		
		
		
		System.out.println(hql);
		
	}
	
	
}

 

 

 

 

 

 

 

注解:

 

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * @Title: PrimaryAnnotation.java
 * @Package com.cai.order.db
 * @Description: TODO(用于标识主键的注解)
 * @author awfhome@163.com
 * @date 2010-3-6 下午02:26:13
 * @version V1.x
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PrimaryAnnotation {
	
}

 

 

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * @Title: FieldAnnotation.java
 * @Package com.cai.order.db
 * @Description: TODO(用于注解数据库表名,字段;对应类的类,属性)
 * @author  awfhome@163.com
 * @date 2010-3-6 下午03:13:51
 * @version V1.x
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldAnnotation {
	String name() default "_null";

}

 

 

model:

 

/**角色*/
@FieldAnnotation(name = "role")
public class Role {
	@PrimaryAnnotation
	private int roleId;
	private String roleName;
	private String description;
	public int getRoleId() {
		return roleId;
	}
	public void setRoleId(int roleId) {
		this.roleId = roleId;
	}
	public String getRoleName() {
		return roleName;
	}
	public void setRoleName(String roleName) {
		this.roleName = roleName;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	
	

}

 

 

 

还有很多没有实现的功能,例如只能标识一个主键和表名,但是数据库字段现在只能和model属性一样,不过实现过程和主键差不多,后来看到了设计模式之模板模式和策略模式如果能结合他们,那就程序就更灵活了,spring的hibernate模板就是用这两种模式来设计的.

 

分享到:
评论
14 楼 fengfeng925 2010-05-27  
linliangyi2007 写道
sunson468 写道
有那么多开源的成熟的架构,除非非常有必要,否则还是拿来主义比较好。

只是研究的话也不错~

顺便感概下,java的反射效率真的不咋地~


我不认为java的反射效率不咋地?楼上的真的试过了吗?没试过不要用自己的感觉来作为判断标准。5.0开始的java已经在类反射上优化了很多。

你可以测试一下用一堆if else和用类反射方式的语句哪个更快,在数量越大的情况下,你会发现,类反射更有效率

说的很对,从jdk1.5开始,虚拟机已经做了很多优化,1.6更比1.5优化了不少。
13 楼 pclfs1983 2010-05-26  
楼上说的很有道理
12 楼 linliangyi2007 2010-05-26  
楼主的工作还是很值得实践一次的,尤其是学习研究阶段。写过和看过代码根本就是两个层次。
11 楼 linliangyi2007 2010-05-26  
sunson468 写道
有那么多开源的成熟的架构,除非非常有必要,否则还是拿来主义比较好。

只是研究的话也不错~

顺便感概下,java的反射效率真的不咋地~


我不认为java的反射效率不咋地?楼上的真的试过了吗?没试过不要用自己的感觉来作为判断标准。5.0开始的java已经在类反射上优化了很多。

你可以测试一下用一堆if else和用类反射方式的语句哪个更快,在数量越大的情况下,你会发现,类反射更有效率
10 楼 crazy.j 2010-05-26  
bluedest 写道
不知道为什么,相当反感注解这种东西

我也一样,看着不规矩!
9 楼 ironsabre 2010-05-26  
aws 写道
另外反射其实也可以把method缓存起来吧


这没用,每个实体对象的属性值还得通过反射来得到。

我这个http://www.iteye.com/topic/675119也用反射实现了一个ActiveRecord,不需要注解,纯约定。

里边有一个地方可以缓存的是数据库结构。只需取一次。
8 楼 aws 2010-05-26  
另外反射其实也可以把method缓存起来吧
7 楼 psuqqvfp 2010-05-26  
反射还可以,不是很占时间
6 楼 bluedest 2010-05-25  
不知道为什么,相当反感注解这种东西
5 楼 tomorrow009 2010-05-25  
J-catTeam 写道
性能的瓶颈不在反射上

仁兄说的对.

对于Java的持久层访问来说,真正瓶颈在于数据库连接的开销,反射虽然不快却并不是短板所在.
4 楼 J-catTeam 2010-05-25  
性能的瓶颈不在反射上
3 楼 hrsvici412 2010-05-25  
哈哈,不怎么的
2 楼 awfrun 2010-05-25  
虽然反射效率不好,但目前我用过的几个开源ORM框架底层都是用反射来实现的.
1 楼 sunson468 2010-05-25  
有那么多开源的成熟的架构,除非非常有必要,否则还是拿来主义比较好。

只是研究的话也不错~

顺便感概下,java的反射效率真的不咋地~

相关推荐

    利用java反射、注解及泛型模拟ORM实现

    这篇博文“利用java反射、注解及泛型模拟ORM实现”旨在探讨如何结合这三种技术来实现对象关系映射(ORM),这是一种将数据库表与Java对象之间进行绑定的技术,简化了数据操作。 首先,我们来理解一下这三个概念: ...

    反射+注解自定义ORM

    在Java编程中,ORM(Object-Relational Mapping)是一种技术,它允许程序员使用面向对象的方式来操作数据库,将数据库中的表映射为Java对象,而无需编写大量的SQL语句。本主题探讨的是如何通过反射和注解来自定义ORM...

    [反射机制]简单实现ORM

    在本案例中,"简单实现ORM"是指通过反射机制来实现对象关系映射(Object-Relational Mapping),这是一种将数据库中的数据与Java对象之间建立映射关系的技术,使得开发者可以更方便地操作数据库。 ORM的主要目的是...

    基于Java动态代理和反射机制实现ORM

    通过阅读和理解这些代码,开发者可以更直观地了解如何在实际项目中应用动态代理和反射实现ORM。 总之,基于Java动态代理和反射机制实现ORM,可以有效地解耦业务逻辑和数据库操作,提高代码的可读性和可维护性。虽然...

    Java-JDBC【源码】实现ORM,结果集映射实体类(ResultSet、注解、反射)

    Java-JDBC【之】实现ORM,结果集映射实体类(ResultSet、注解、反射) 1.ORM实现思路 2.@Table、@Column、标识实体类 2.1.创建注解 @Table、@Column 2.2.标识实体类 2.3.数据库表 3.结果集解析,注解加反射填充实体...

    一种基于反射和注解的HBase-ORM框架.pdf

    HBase-ORM框架的主要特点是使用Java的反射和注解技术来完成数据的映射关系,能够自动建立底层数据库表与上层数据库对象之间的映射关系,并且能够根据不同的数据类型来建立索引,实现了文本的模糊查询、数值的区间...

    自定义Orm框架的实现

    ORM(Object-Relational Mapping,对象关系映射)框架是一种技术,它允许程序员用面向对象的方式操作数据库,而无需关心底层SQL语句的编写。在Java领域,Hibernate是一个非常流行的ORM框架,它极大地简化了数据库...

    AndroidInject增加sqlite3数据库映射注解(ORM).zip

    本项目"AndroidInject增加sqlite3数据库映射注解(ORM)"旨在介绍如何通过注解的方式实现SQLite数据库的ORM(Object-Relational Mapping)映射,以简化数据库操作。ORM是一种技术,它允许开发者使用面向对象的方式来操作...

    .net 简单实现orm实例

    ORM,全称Object-Relational Mapping,即对象关系映射,是一种编程技术,用于将关系数据库的数据映射到...在实际项目中,虽然简单的反射实现可能效率较低,但对于理解ORM的工作方式和自定义需求,这是一个很好的起点。

    AndroidInject增加sqlite3数据库映射注解(ORM)

    AndroidInject库正是这样一个帮助开发者实现ORM的工具,它允许开发者通过注解来实现SQLite3数据库的映射。 首先,让我们深入理解AndroidInject的ORM机制。ORM的核心是将Java对象与数据库表进行映射,通过注解,我们...

    基于注解的hbase orm小工具,目前比较简单

    在HBase中,ORM工具可以使开发者无需直接编写HBase的Put、Get、Scan等操作,而是通过定义对象和注解的方式,实现数据的存取。 **HBase ORM工具的特点** 这个基于注解的HBase ORM小工具,虽然目前设计简单,但它的...

    Android高级应用源码-AndroidInject增加sqlite3数据库映射注解(ORM).zip

    这个压缩包"Android高级应用源码-AndroidInject增加sqlite3数据库映射注解(ORM).zip"提供了一个示例,展示了如何在Android项目中使用SQLite3数据库,并通过ORM(对象关系映射)技术来简化数据库操作。ORM允许开发者...

    java注解、java反射机制 jdbc 封装

    文件`annotation_orm`可能包含了实现这些功能的核心代码,如注解定义、反射处理逻辑以及JDBC操作的封装。通过学习这个案例,开发者可以深入理解如何在实际项目中有效利用Java的注解和反射机制,提升代码质量和可维护...

    python实现orm

    Python ORM(对象关系映射)是一种编程技术,用于将数据库操作转化为对对象的操作,使得开发者可以使用面向对象的方式来处理数据库,而无需关心底层SQL语句的编写。这大大提高了开发效率,降低了数据库操作的复杂性...

    基于java 简易ORM 框架实现(一)

    在自定义的简易ORM框架中,我们可能首先需要实现一个基础的实体类模板,然后设计一个映射解析器来读取注解信息并生成SQL。接着,构建数据库连接池和事务管理器。最后,提供一套易于使用的API供用户进行数据操作。 ...

    AndroidInject增加sqlite3数据库映射注解(ORM).rar

    本话题主要探讨如何在Android中使用SQLite数据库,并通过AndroidInject库和sqlite3注解实现对象关系映射(ORM),以简化数据库操作。ORM允许开发者用面向对象的方式来处理数据库,而无需直接编写SQL语句,提高了代码...

    Android高级应用源码-AndroidInject增加sqlite3数据库映射注解(ORM).rar

    这个压缩包"Android高级应用源码-AndroidInject增加sqlite3数据库映射注解(ORM).rar"提供了一个示例,展示了如何在Android项目中使用SQLite3数据库,并结合ORM(对象关系映射)技术,通过注解的方式简化数据库操作。...

    C#发现之旅:使用反射和特性构造自己的ORM框架实用.pdf

    在IT领域,ORM(Object-Relational Mapping,对象关系映射)是一种技术,它允许开发者在使用面向对象编程语言时,无需关注底层数据库的具体细节,就能处理关系型数据库中的数据。ORM框架通过创建对象和数据库表之间...

    @TypeDiscriminator注解实现多态对象的查询,jackson @JsonTypeInfo注解实现controller多态支持

    当我们有一个基类和多个子类,并且希望在数据库中存储这些子类实例时,这个注解就非常有用。例如,假设我们有`Animal`基类和`Dog`、`Cat`两个子类,`@TypeDiscriminator`可以让我们指定一个字段(如"type")来区分...

    ORM技术的简单实现CRUD

    采用Java反射技术实现ORM技术,通过操作对象就可以操作数据库。 本例子采用Eclipse , Java 7.0 , apache DBCP, Spring 3.1等开源框架, 数据库JDBC 采用oracle jdbc. 文件分为两部分, 一部分是基于Eclipse 的ORM的...

Global site tag (gtag.js) - Google Analytics