几种面向对象的数据库访问策略:
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();
============
总得来说,使用反射机制可以极大得方便对数据的各种操作,使操作变得更加透明,无需配置文件
新闻热点
疑难解答