之所以会写这个程序完全是因为偷懒^^,那时在公司实习要我们用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 [email protected] * @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 [email protected] * @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 [email protected] * @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模板就是用这两种模式来设计的.