曾经用过同事的一个基于Hibernate的通用增删改查框架,当时我的感觉相方便,简直是开发小型项目的不二选择,并且那个‘框架’也做为了当时公司里的标准。

 

膜拜归膜拜,勤于钻研善学善用是鞭长一族的传统美德!作为鞭长创始人阿海,我认为膜拜的同时更有必要将其技术学为己用。

还好Eclipse中带有一个反编译的插件,可以清楚的看到Jar包中的源代码,经过一下午的研究,得出结论:

       其实也就那么回事儿,吧PO类通过反射动态转换成了HQL语句。

       毫不夸张的说,这东西我闭着眼睛也能做出来^.^~

既然要做,那就做的彻底一些,既然要封装,那就从底层真正封装成为一个属于自己的框架!

遵从阿海的一贯作风,说干就干,首先花了半个小时温习了一下JDBC的知识,又抽时间在网上浏览了一些数据库底层的框架,还看过Mybatis和Hibernate的源码,虽然看不太懂,但对他们的基本工作模式也是有了一定的深入的了解。

于是就开写了,同样是根据数据库驱动封装成对应的SQL语句,什么增删改查拉,各种花式查询啦,开干!

 

这套数据库框架也没有想过什么霸气的名字,我且叫他CRUD框架。有的时候我会向朋友们戏称为《大屌牌儿CRUD框架》

说到这里,且听我先介绍一下这套RCUD框架的结构。

       大体也就分为五个部分,因为是初做,没有什么缓存之类的东西,但是他相对于Hibernate以及同事的那个基于Hibernate来说,有一个很有效率的亮点,就是所谓的动态Sql。

 

1、动态Sql算是一部分吧,他是基于一个支持链式操作的WherePrams类实现Sql的生成。

 

2、再有就是数据库访问层,这里是和C3P0进行整合,使用的C3P0连接池,并且在其基础上进行装饰,让Spring代理了他的SqlSession链接,方便对事物的控制。

 

3、然后是一个反射类,这里他主要是获取一个实体类的fields,和类名以及实体类中的类注解、字段注解。并且负责对SqlResult的封装。

 

4、便是注解部分类,注解大部分用作标识,例如@TempField表示非入库字段(临时字段,不计入增删改查的操作)、@ID、@TabName、@FieldName之类的。则标识实体类数据库中对应的表名和字段。若没有写该注解的话,CRUD框架则会用类名和字段名作为表和字段的查询(会自动将驼峰标识格式化为下划线分割)

 

5、事务处理类,这个是后来加上的,一开始准备用Spring的@Transactional控制事务,但是实际测试不但起不到效果,还会有冲突,具体是如何将事务托管给Spring我还是不太清楚。我看的Mybatis源码中页没有Spring-mybatis整合包的源码,所以无从下手,所以不久我便自己写了一个事务处理机制,用的是@TranMethod方法,这个方法可以标注到Service方法中,也可以标注到Controller方法中。在Controller方法中则该次请求都算作一个事务,在Service中,则一个方法算是一个事务。我一般飙在Controller方法上。

 

先从动态SQL,大家可能会首先想到MyBatis,的确,MuBatis的亮点之一就是动态可配的软编码Sql。

而我的所说的这个动态SQL属于硬编码,但不要听到硬编码就不屑一顾,其实开发后期改库的可能性并不大,也很少有人在后期修改MyBatis的Mapper文件,至少我是这样。有的时候虽然避免不了增改字段,但是这的确属于极少数,即使遇到这种情况,我认为我会接受重新把项目编译一下的方案。再者,开发阶段我更乐意把精力集中到业务上。还有一个原因就是硬编码的开发成本实在是太低了,所以我选择了硬编码。

之所以这么重点的强调动态SQL,是因为他实在是太他妈的完美了,他支持链式操作,一个简单的查询完全可以写成Method.createDefault();

通常的查询吧,也是相当方便:

List list = list(POJO.class,

Method.where(xxx,C.xx, xxxx)

.and(xxx, xx, xx)

.or(xxx, xxx, xx)

.in(listField(POPO.class, fieldname, Method.where(xxx, xxx, xxx)))

);

吹了这么多,相信一些用心的朋友可能看出这个框架的中心结构了,中心结构就是一个Where类,这个Where是一个可以链式操作的类,类似于StringBuffer的append()方法。

同时,也通过递归的方式支持了嵌套操作。

他可以将复杂的函数格式化为一条完整的高级Sql,不需要多次查询,这点儿灵活性和易用性,是朋友那个Hibernate框架不能比拟的。

举个简单嵌套查询名为Po的这个类的例子:

       CRUD框架:

       List list = list(Po.class, Method.createDefault().in( aid,

 listField(Apo.class, id, Method.where( sex, C.Eq , 1));

));

 

同事基于Hibernate的封装:

String[] filed = {id};

//第一次查询(Integer.MAXVALUE是用来分页的,前者要分页的话,可以直链式追加limit()方法)

List idLIst =  listPropinoty(Apo.class, Factory.create(sex, C.eq , 1),0, Integer.MAXVALUE , filed);

 

String[] ids = idLIst.toArray(String.class, idLIst.size());

//第二次查询

List list = list(Po.class , 0, Integer.MAXVALUE , Factory.create( aid, ids));

 

不难看出,前者一次查询就够了,后者则需要两次查询。

 

如果对比不明显的话那么,再举一个简单的例子:

CRUD 框架(一条Sql搞定,采用链表+别名的方式实现)

List list = List(Po.class, Method.createDefault()

.framTo(img, ImgResource.class, id, url));

 

基于Hibernate的封装:

       List list = list(Po.class, 0, Integer.MAXVALUE);

 

       for(Po po : list){

//看,又开始查询了,而且是循环查询,例如上面list中有100个Po的话,就要    循环查询100次,假如一千条甚至一万条呢?

              ImgResource img = list(ImgResource.class, 0, Integer.MAXVALUE,

Factory.create(id, C.eq, po.getImg()));

             

              if(null != img){

                     po.setImg(img.getUrl());

}

             

}

 

不多吹了,吹了这么多到头来,《大屌牌儿CRUD框架》仍然是一个失败品。为谁么这么说呢,我虽然对他进行了了简单的测试,然而并没有把他应用到项目中。一直到阿海开发一套拥有IM服务的《鞭长网络用户管理平台》时,才加以使用,开发很顺畅,然而部署到服务器中了以后,才发现《大屌牌儿CRUD框架》有致命的BUG,为什么说致命呢?因为运行两天后,他就挂了!

挂了就重启,重启了就又挂。。。反反复复,阿海也试着再找原因,但是一直没有找到。

 

看来还是技术不够成熟,所以,暂时先放下自己开发框架的这个幼稚的想法,转攻Mybatis!准备把Mybatis封装的像《大屌牌儿CRUD框架》一样神奇。

 

当然,Mybatis我是封装成功了的,不然我也不会写这篇文章了,本来想出一篇文章概括完,结果写起来才发现,要写的东西实在是太多了,所以阿海尽量精简,然而前言刚介绍完毕,就发现已经码了很多字了,或许是有敲代码的功底,才让我坚持敲到这里的。

 

哦了,回头继续发布《通用DAO之MyBatis封装,封装通用的增删改查(二)。》


Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐