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