首页 > 开发 > PHP > 正文

J2EE中几种面向对象的数据库映射访问策略:

2024-05-04 22:58:58
字体:
来源:转载
供稿:网友

几种面向对象的数据库访问策略:

1 jdbc
是最原始的方法,写sql语句,维护性差


下面面向对象的方法:

例如update: 要先取出对象,更新对象,然后再保存

orderinfo order = orderservice.getorder(orderid);
order.setstatus(new integer(2));
orderservice.updateorder(order);

2 hibernate

使用hql

3 ibatis
将查询和更新放在maps文件中

  <dynamic-mapped-statement name="searchproductlist" result-map="result">
    select productid, name, descn, category from product
    <dynamic prepend="where">
      <iterate property="keywordlist" open="(" close=")" conjunction="or">
        lower(name) like #keywordlist[]# or lower(category) like #keywordlist[]# or lower(descn) like #keywordlist[]#
      </iterate>
    </dynamic>

4 easydbo:

有三种实现方法,我们只看其中采用annotation的
@table(tablename="customer")
public class customer implements serializable {
来确定表名

采用反射的方法,不需要配置文件:
 public list getrootcustomers() { 
  return this.dao.query(customer.class,"(parent_id is null or parent_id='')");
 }

  list list=dao.query(customerprice.class, "customer_id="+cu.getid()+" and product_id="+p.getid()+" order by vdate desc");

该方法已经和adodb很像了,但和adodb不同的是,仍然没有实现完全自动的plain sql转换到po.

5 php's adodb的j2ee移植

以jdbc查询sql为基础,通过反射,范型等方法自动装载。
adodb的方法和上面的easydbo很像,不过在obj到sql的生成上更加成熟一些,驱动也更加多

对于查询

    /////////////////////////////////////////////////////////////////////////////
    //function: 完成resultset对象向arraylist对象为集合的对象的转化
    //para:sql,指定的查询sql
   //para:classname,sql相对应得javabean/formbean类的名字
   //return:以类classname为一条记录的结果集,完成resultset对象向arraylist对象为集//合的classname对象的转化
  //////////////////////////////////////////////////////////////////////////////
  public arraylist select(string sql,string classname){
    arraylist paralist=new arraylist();
    try{
      if (conn == null){
        connection();
      }
      preparedstatement stmt = conn.preparestatement(sql);
      resultset rs = stmt.executequery();
      string recordvalue="";
      object c1=null;
      paralist=new arraylist();
      resultsetmetadata rsmd = rs.getmetadata();
      int columncount = rsmd.getcolumncount();
      while (rs.next()){
          c1=class.forname(classname).newinstance();
          for (int i=1; i<=columncount; i++) {
            if(rs.getstring(rsmd.getcolumnname(i))!=null){
              recordvalue=rs.getstring(rsmd.getcolumnname(i));
            }else{
              recordvalue="";
            }
            method m=c1.getclass().getmethod(getsetmethodname(rsmd.getcolumnname(i)),new class[]{recordvalue.getclass()});
            m.invoke (c1, new object[]{recordvalue});
          }
          paralist.add(c1);
      }
    }catch(sqlexception ex){
     
    }catch(classnotfoundexception e){
    }catch(nosuchmethodexception e) {
    }catch(invocationtargetexception e){
    }catch (illegalaccessexception e){
    }catch(instantiationexception e){
    } finaly{
        closeconnection();
    return paralist;
    }
      }


   //function:取得用户列表
  //para:
  //return:返回用户列表
  /////////////////////////////////////////////////////////////////////////////
  public arraylist getusers(){
      arraylist ret=null;
      databasemanage db=new databasemanage();
      string sql=" select usr_id,usr_name "
          +" from users " ;  //该方法的好处是sql可以随便写,需要的字段也可以随便写,甚至免去了持久层的lazyload
      ret=db.select(sql,"com.domain.user");
      return ret;
  }

对于单张表,用po/formbean来存放
如果有关联多张表,需要一个vo/map来存放

对于保存和更新
    检查对象里面的每一个属性,如果不是null,就组成sql语句,
    更新的时候,先查出这个对象,如果属性不是null,并且属性值变了,才将该属性组成sql语句
   
这种方法和hibernate/ibatis相比可能牺牲一些性能,但是免去了大量的配置文件,如果对字段有特殊的要求,可以
通过annotation来定义。

annotation可是个好东西,根据jdk手册:annotations can be read from source files, class files, or reflectively at run time.
所以可以充分利用反射读取annotation来减少代码。
下面是一些例子
@com.acme.util.name(first=alfred, middle=e., last=neuman)
@table(tablename="customer")
@manytoone(column = "parent_id", fieldtype=java.util.hashset.class,type = customer.class,lazy=false)
读取的方法是在反射里面使用下面的方法
<t extends annotation> t xxx = getannotation(class<t> annotationclass) 

当然,实现必须声明annotationclass,下面是手册的一个简单例子
/**
 * describes the request-for-enhancement(rfe) that led
 * to the presence of the annotated api element.
   定义一个标签记号
 */
public @interface requestforenhancement {
    int    id();
    string synopsis();
    string engineer() default "[unassigned]";
    string date();    default "[unimplemented]";
}

这个标签,和它的属性都在上面声明了,下面是某个函数中需要用到这个标签的示例
@requestforenhancement(
    id       = 2868724,
    synopsis = "enable time-travel",
    engineer = "mr. peabody",
    date     = "4/1/3007"
)
public static void travelthroughtime(date destination) { ... }

因此我们如果想要调用这个标签
for (method m : class.forname('假设是travelthroughtime所在的类名').getmethods()) {
         if (m.isannotationpresent(requestforenhancement.class)) {
             requestforenhancement rfe = m.getannotation(requestforenhancement.class);
             下面就可以取得rfe的属性了
         }
      }

commons attributes也是一个替代jdk标准annotation的方案


php中的adodb之所以强大,高效是在于php数组的强大和弱变量定义的方便。

当然这里的每一个对象就相当于对应数据库的一张表,这样也很好。
因为在业务相当复杂的时候,关联要尽量少用,把业务精心设计在数据库表上面而非java对象的集合的关联上。
在大型应用中,一般1:1的关联都多使用view来处理关联,1:n和n:n的关联,建议还是在dao里面手动保存,装载和更新


===================
此外还有一些方法,可以方便我们快速的将rs变成可操作的对象,简单举几个例子如下

1 commons dbutils

custom rowprocessor

java.lang.object[] toarray(java.sql.resultset rs)
          convert a resultset row into an object[].
 java.lang.object tobean(java.sql.resultset rs, java.lang.class type)
          convert a resultset row into a javabean.
 java.util.list tobeanlist(java.sql.resultset rs, java.lang.class type)
          convert a resultset into a list of javabeans.
 java.util.map tomap(java.sql.resultset rs)
          convert a resultset row into a map.


custom beanprocessor


 java.lang.object tobean(java.sql.resultset rs, java.lang.class type)
          convert a resultset row into a javabean.
 java.util.list tobeanlist(java.sql.resultset rs, java.lang.class type)
          convert a resultset into a list of javabeans.


2 commons beanutils
resultsetdynaclass (wraps resultset in dynabeans)

  connection conn = ...;
  statement stmt = conn.createstatement();
  resultset rs = stmt.executequery
    ("select account_id, name from customers");
  iterator rows = (new resultsetdynaclass(rs)).iterator();
  while (rows.hasnext()) {
    dynabean row = (dynabean) rows.next();
    system.out.println("account number is " +
                       row.get("account_id") +
                       " and name is " + row.get("name"));
  }
  rs.close();
  stmt.close();

============

总得来说,使用反射机制可以极大得方便对数据的各种操作,使操作变得更加透明,无需配置文件


 

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表