您的位置:首页 > 其它

通用DAO之MyBatis封装,封装通用的增删改查(一)

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


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

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

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

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

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

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

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

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

大体也就分为五个部分,因为是初做,没有什么缓存之类的东西,但是他相对于
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("fieldName",C.Eq, "value")
.and("fieldName",C.Like, "value")
.or("fieldName",C.Da, "value")
.in(
"SelectFieldName",
listField(
POPO.class, "SelectFieldName", Method.where("fieldName", C.Eq, "value")
)
)
);


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

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

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

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

CRUD框架:

//查询Po中,aid与(Apo中sex=1的id)相同的字段
List<Po> 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<Object> idLIst =  listPropinoty(
Apo.class, Factory.create("sex", C.eq , 1),0, Integer.MAXVALUE , filed
);

String[] ids = idLIst.toArray(String.class, idLIst.size());
//第二次查询
List<Po> list = list(Po.class , 0, Integer.MAXVALUE , Factory.create("aid", C.in, ids));


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

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

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

List<Po> list = List(Po.class, Method.createDefault()
.fromTo("img", ImgResource.class, "id", "url"));


基于Hibernate的封装:

List<Po> 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封装,封装通用的增删改查(二)。》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息