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