自己实现ORM

这篇文章源自刚开发的一个小项目。项目中并未使用hibernate,但我还是要把它放在hibernate栏下。理由很简单,技术是死的,而人是活的,能熟练的使用一项技术不算什么,但能恰当的选择相应的技术,甚至自己想出办法来优雅的解决实际问题,就需要一定的积累了。而这种积累就来源自项目实践和对各种技术其实质的理解。我记得在某个论坛上某人(名字忘了)说过一句话:如果学习hibernate只是学会了怎么mapping,怎么写DAO,就只是学了皮毛,学hibernate就要从中了解到很多持久层的最佳实践。我深以为然!

项目很简单,页面也不多,但页面字段较多(100多个),相互间还有一定关联。而且存入数据库类型多样,有varchar, integerdate几种。我是很希望用hibernate来实现的,但考虑到项目时间较紧,而我对hibernate的了解还是停留在理论和学习阶段(有点落后啊!),采用不熟悉的技术项目风险较大,所以还是使用普通JDBC作为持久层方案。面对这么多字段,一个个去拼SQL语句,代码臃肿,而且容易出错,也难以维护。我得对这几种类型的字段,在插入、更新和读取时分别处理,写一个private方法,传入类型和字段名,读取相应的ResultSet,是不错的方法,至少是比较优雅的实现。

什么是优雅?动态设置,避免hardcode,就是优雅;层次清晰,层次间耦合最低,就是优雅;只写一处,处处引用,就是优雅;代码精炼,避免过度设计,就是优雅;接口明确,调用简单,就是优雅;调试容易,便于测试,就是优雅。。。。。。而优雅的设计和实现,在可扩展性、可维护性、开发效率、开发成本等方面都是最好的。

Hibernate就是优雅的设计,它通过配置文件,建立实体与数据库的映射,动态的生成SQL语句,避免了对属性字段的hardcode,这就是它最本质的思想。我不使用hibernate,但一样可以借鉴它的思想,我不需要对象容器、分页查询等等高级功能,因此可以简单的实现类似ORM的功能。

首先,定义一个配置类,将数据库字段和类型定义下来。按照常规的做法,从页面字段到对象属性到数据库都应该建立映射,这样需要生成相应的映射类。为简单起见,我不使用POJO,而是使用Map作为数据的载体,key就是数据库字段名,在页面端我也用数据库字段名作为域的名称。这样我直接通过名称建立映射,牺牲了扩展性和灵活性,但简化了操作,也无需映射类,只要一个映射Mapkey是数据库字段名,value是我自己定义的字段类型。以后动态生成SQLMap传输对象,以及从页面request动态生成Map都是基于这个配置。

接下来,就很简单了。先处理DAO的动态生成SQL代码,下面是生成insertSQL的方法,

ExpandedBlockStart.gif ContractedBlock.gif private   static  String generateInsertScoreSQL(Map m, String studentId)  dot.gif {
InBlock.gif
InBlock.gif              StringBuffer sb 
= new StringBuffer();
InBlock.gif
InBlock.gif              StringBuffer sb2 
= new StringBuffer();
InBlock.gif
InBlock.gif 
InBlock.gif
InBlock.gif              sb.append(
"insert into STUDENT_SCORE (id,");
InBlock.gif
InBlock.gif              sb2.append(
" values('");
InBlock.gif
InBlock.gif              sb2.append(studentId);
InBlock.gif
InBlock.gif              sb2.append(
"',");
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif              
for (Iterator iter = m.keySet().iterator(); iter.hasNext();) dot.gif{
InBlock.gif
InBlock.gif                     String name 
= (String) iter.next();
InBlock.gif
InBlock.gif                     String value 
= (String) m.get(name);
InBlock.gif
InBlock.gif                     sb.append(name);
InBlock.gif
InBlock.gif                     sb.append(
",");
InBlock.gif
InBlock.gif 
InBlock.gif
InBlock.gif                     String type 
= (String) ScoreColumnMapping.scoreItemMap().get(name);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                     
if (ScoreColumnMapping.INT.equalsIgnoreCase(type)) dot.gif{
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                            
if (value == null || value.length() == 0dot.gif{
InBlock.gif
InBlock.gif                                   sb2.append(
"null,");
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                            }
 else dot.gif{
InBlock.gif
InBlock.gif                                   sb2.append(Integer.parseInt(value));
InBlock.gif
InBlock.gif                                   sb2.append(
",");
InBlock.gif
ExpandedSubBlockEnd.gif                            }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                     }
 else if (ScoreColumnMapping.STRING.equalsIgnoreCase(type)) dot.gif{
InBlock.gif
InBlock.gif                            sb2.append(
"'");
InBlock.gif
InBlock.gif                            sb2.append(value);
InBlock.gif
InBlock.gif                            sb2.append(
"',");
InBlock.gif
ExpandedSubBlockEnd.gif                     }

InBlock.gif
ExpandedSubBlockEnd.gif              }

InBlock.gif
InBlock.gif              sb.replace(sb.length() 
- 1, sb.length(), ")");
InBlock.gif
InBlock.gif              sb2.replace(sb2.length() 
- 1, sb2.length(), ")");
InBlock.gif
InBlock.gif              log.info(sb.toString() 
+ sb2.toString());
InBlock.gif
InBlock.gif              
return sb.toString() + sb2.toString();
InBlock.gif
ExpandedBlockEnd.gif       }

None.gif

生成updateSQL的代码:

     

ExpandedBlockStart.gif ContractedBlock.gif    private   static  String generateUpdateScoreSQL(Map m, String studentId)  dot.gif {
InBlock.gif
InBlock.gif              StringBuffer sb 
= new StringBuffer();
InBlock.gif
InBlock.gif 
InBlock.gif
InBlock.gif              sb.append(
"update STUDENT_SCORE set ");
InBlock.gif
InBlock.gif 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif              
for (Iterator iter = m.keySet().iterator(); iter.hasNext();) dot.gif{
InBlock.gif
InBlock.gif                     String name 
= (String) iter.next();
InBlock.gif
InBlock.gif                     String value 
= (String) m.get(name);
InBlock.gif
InBlock.gif                     sb.append(name);
InBlock.gif
InBlock.gif                     sb.append(
"=");
InBlock.gif
InBlock.gif 
InBlock.gif
InBlock.gif                     String type 
= (String) ScoreColumnMapping.scoreItemMap().get(name);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                     
if (ScoreColumnMapping.INT.equalsIgnoreCase(type)) dot.gif{
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                            
if (value == null || value.length() == 0dot.gif{
InBlock.gif
InBlock.gif                                   sb.append(
"null,");
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                            }
 else dot.gif{
InBlock.gif
InBlock.gif                                   sb.append(Integer.parseInt(value));
InBlock.gif
InBlock.gif                                   sb.append(
",");
InBlock.gif
ExpandedSubBlockEnd.gif                            }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                     }
 else if (ScoreColumnMapping.STRING.equalsIgnoreCase(type)) dot.gif{
InBlock.gif
InBlock.gif                            sb.append(
"'");
InBlock.gif
InBlock.gif                            sb.append(value);
InBlock.gif
InBlock.gif                            sb.append(
"',");
InBlock.gif
ExpandedSubBlockEnd.gif                     }

InBlock.gif
ExpandedSubBlockEnd.gif              }

InBlock.gif
InBlock.gif              sb.replace(sb.length() 
- 1, sb.length(), "");
InBlock.gif
InBlock.gif 
InBlock.gif
InBlock.gif              sb.append(
" where id='");
InBlock.gif
InBlock.gif              sb.append(studentId);
InBlock.gif
InBlock.gif              sb.append(
"'");
InBlock.gif
InBlock.gif 
InBlock.gif
InBlock.gif              log.info(sb.toString());
InBlock.gif
InBlock.gif              
return sb.toString();
InBlock.gif
ExpandedBlockEnd.gif       }

None.gif

ResultSet中生成Map对象的代码:

ExpandedBlockStart.gif ContractedBlock.gif private   static   void  getScoreFromRs(ResultSet rs, Map m)  throws  SQLException  dot.gif {
InBlock.gif
InBlock.gif              String name;
InBlock.gif
InBlock.gif              String type;
InBlock.gif
InBlock.gif              
for (Iterator iter = ScoreColumnMapping.scoreItemMap().keySet()
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                            .iterator(); iter.hasNext();) 
dot.gif{
InBlock.gif
InBlock.gif                     name 
= (String) iter.next();
InBlock.gif
InBlock.gif                     type 
= (String) ScoreColumnMapping.scoreItemMap().get(name);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                     
if (ScoreColumnMapping.INT.equalsIgnoreCase(type)) dot.gif{
InBlock.gif
InBlock.gif                            Object value 
= rs.getObject(name);
InBlock.gif
InBlock.gif                            m.put(name, String.valueOf(value 
== null ? "" : value));
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                     }
 else if (ScoreColumnMapping.STRING.equalsIgnoreCase(type)) dot.gif{
InBlock.gif
InBlock.gif                            String value 
= rs.getString(name);
InBlock.gif
InBlock.gif                            m.put(name, value);
InBlock.gif
ExpandedSubBlockEnd.gif                     }

InBlock.gif
ExpandedSubBlockEnd.gif              }

InBlock.gif
InBlock.gif 
InBlock.gif
ExpandedBlockEnd.gif       }

None.gif

因为只有一个DAO采用这种方式,所以我用private方法,这可以通过重构,将其抽取到Util类中,供所有DAO使用。页面端也很简单,我做个Façade类,它获取request,并将其处理成一个Map,然后交给数据层处理(因为比较简单,省去了业务层),代码如下:

<o:p>

None.gif Map m  =   new  HashMap();
None.gif
None.gif        
for  (Iterator iter  =  ScoreColumnMapping.scoreItemMap().keySet()
None.gif
ExpandedBlockStart.gifContractedBlock.gif                .iterator(); iter.hasNext();) 
dot.gif {
InBlock.gif
InBlock.gif            String name 
= (String) iter.next();
InBlock.gif
InBlock.gif            String value 
= request.getParameter(name);
InBlock.gif
InBlock.gif                     ……
InBlock.gif
InBlock.gifm.put(name, value);
InBlock.gif
InBlock.gif……
InBlock.gif

 </o:p>

所有方法中未出现一个字段名称,全部是从配置类中动态生成。这样带来了很多好处:

u       扩展容易,如果需增加字段,无需更改核心代码,只要修改配置文件和数据库表定义,然后页面上加加域

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值