博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
闲话iBatis
阅读量:6594 次
发布时间:2019-06-24

本文共 8667 字,大约阅读时间需要 28 分钟。

使用iBatis开发已经有一年了,这一年来不管愿意不愿意,喜欢不喜欢,都得用,想用Hibernate不行。
 
随着对iBatis的熟悉,渐渐发现初次接触的人因为不能很好的掌握iBatis使用的方法而对其有一些偏激的看法。
 
1、iBatis的是用来自由写SQL的,对SQL语句的简单的封装,相当于在JDBC上加了层外壳。
我认为,iBatis的目标是简化JDBC的操作,对SQL的查询结果做了很好的映射封装,这样查询的结果就形成了一个java对象、集合、或者Map等。这样的数据结构相比JDBC结果集的处理是一个质的飞跃。
 
iBatis虽然支持随意的SQL查询,并且对查询结果集也没有什么特别限制,最懒惰的是定义查询结果集类型为map。但是,这并不是iBatis设计者的本意,我认为,在使用iBatis的时候,尽可能写通用的增删改差sql,然后通过通过这些sql所对应DAO方法的组合,来实现各种业务,而不是写很多特殊的sql、甚至存储过程。当你在更换数据库的时候,移植这些特殊sql和过程就是一件很困难的事情。
 
2、iBatis映射太麻烦,表字段和实体(Entity,也有人称POJO)对应比较麻烦,不够直观,开发困难。
其实,最好的做法就是使用数据库表字段名作为实体的属性名,这样完全对应起来,问题就解决了。并且,可以写个工具,从数据库生成POJO和SQLMap、DAO、Service等等。这样可以极大提高效率,我就这么做的。
 
3、iBatis分页是内存分页,假分页
的确如此,对于小数据量是够用了,对于大数据量,这是不可接受的。因此可以通过动态SqL来拼装分页查询Sql。
                
<
dynamic prepend=""
> 

                        
<
isNotNull 
property
="_start"
> 

                                
<
isNotNull 
property
="_size"
> 

                                        limit #_start#, #_size# 

                                
</
isNotNull
> 

                        
</
isNotNull
> 

                
</
dynamic
> 

 
4、iBatis无法做成Hibernate那样的关连查询、级联保存、级联删除。
iBatis可以做到,而且实现很灵活方便。但是比Hibernate操作更容易,也很好理解。这里面对结果集映射类型也很讲究。
        
<
resultMap 
id
="result_base" 
class
="Channel"
> 

                
<
result 
property
="id" 
column
="id"
/> 

                
<
result 
property
="stationid" 
column
="stationid"
/> 

                
<
result 
property
="remark" 
column
="remark"
/> 

                
<
result 
property
="status" 
column
="status"
/> 

        
</
resultMap
> 

        
<
resultMap 
id
="result" 
class
="Channel" 
extends
="channel.result_base"
> 

                
<
result 
property
="cfgList" 
column
="id" 
select
="videoregxp.findByChannelId"
/> 

        
</
resultMap
>
 
  
<
resultMap 
id
="result_base" 
class
="Videoregxp"
> 

    
<
result 
property
="id" 
column
="id"
/> 

    
<
result 
property
="lmid" 
column
="lmid"
/> 

    
<
result 
property
="name" 
column
="name"
/> 

    
<
result 
property
="cname" 
column
="cname"
/> 

    
<
result 
property
="sortnum" 
column
="sortnum"
/> 

    
<
result 
property
="remark" 
column
="remark"
/> 

  
</
resultMap
> 

        
<
resultMap 
id
="result" 
class
="Videoregxp" 
extends
="videoregxp.result_base"
> 

                
<
result 
property
="regex" 
column
="id" 
select
="regexpar.findByVideoregxpId"
/> 

        
</
resultMap
>
 
        
/** 
         * 保存一个视频信息,级联保存相关的剧集和视频分段文件 
         * 
         * @param videoinfo 视频信息对象 
         * @return 返回保存后的对象 
         */
 

        
public Videoinfo saveVideoinfoWithCascade(Videoinfo videoinfo) { 

                videoinfoDAO.saveVideoinfo(videoinfo); 

                
for (Juji juji : videoinfo.getJujiList()) { 

                        juji.setVideoid(videoinfo.getId()); 

                        jujiDAO.saveJuji(juji); 

                        
for (Secfiles file : juji.getSecfileList()) { 

                                file.setSegmentid(juji.getId()); 

                                secfilesDAO.saveSecfiles(file); 

                        } 

                } 

                
return videoinfo; 

        }
 
        
/** 
         * 删除指定标识的一个栏目 
         * 
         * @param id 栏目标识 
         */
 

        
public 
void deleteChannelById(Long id) { 

                
//todo:做可行性校验,以及级联删除等操作,并做业务特殊需求校验 

                Channel ch = channelDAO.findChannelById(id); 

                
for (Videoregxp v : ch.getCfgList()) { 

                        regexparDAO.deleteRegexparByCfgId(v.getId()); 

                } 

                videoregxpDAO.deleteVideoregxpByLmId(ch.getId()); 

                channelDAO.deleteChannelById(id); 

        }
 
5、iBatis延迟加载好像有问题,本人现在不能确信。
 
6、iBatis用熟悉了和Hibernate一样容易,通过自己开发工具,可以极大提高开发效率。我会在附件贡献出我的代码生成工具。
 
7、iBatis的cache缓存没感觉到有多大优势,也没感觉性能的提升。
 
8、iBatis的动态SQL功能强大,Map参数更能获取最大的灵活性,这是Hibernate和其他持久化框架所无法相比的。
        
<
select 
id
="findByParams" 
parameterClass
="map" 
resultMap
="channel.result"
> 

                
<
include 
refid
="sql_select"
/> 

                
<
include 
refid
="sql_where"
/> 

        
</
select
> 

 
        
/** 
         * 根据动态条件查询栏目 
         * 
         * @param map 参数map 
         * @return 查询结果集 
         */
 

        
public List<Channel> findChannelByParams(Map map) { 

                
return getSqlMapClientTemplate().queryForList(
"channel.findByParams", map); 

        }
 
但是map参数也缺乏明确性,使用者无法清楚知道map参数里面究竟可以传什么类型,但是使用者可以通过查看sqlMap进一步获得对参数的详细认识,比如上面的完整SQLMap片段是:
 
        <!--
 动态条件分页查询 --> 

        
<
sql 
id
="sql_count"
> 

                select count(*) 

        
</
sql
> 

        
<
sql 
id
="sql_select"
> 

                select * 

        
</
sql
> 

        
<
sql 
id
="sql_where"
> 

                from channel 

                
<
dynamic 
prepend
="where"
> 

                        
<
isNotNull 
prepend
="and" 
property
="stationid"
> 

                                stationid = #stationid# 

                        
</
isNotNull
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="name"
> 

                                name like '%$name$%' 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="url"
> 

                                url like '%$url$%' 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="regxp"
> 

                                regxp like '$regxp$%' 

                        
</
isNotEmpty
> 

                        
<
isNotNull 
prepend
="and" 
property
="encoding"
> 

                                encoding = #encoding# 

                        
</
isNotNull
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="_timeout_ge"
> 

                                <![CDATA[ 

                                timeout >= #_timeout_ge# 

                        ]]> 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="_timeout_lt"
> 

                                <![CDATA[ 

                                timeout 
<
 #_timeout_lt# 

                        ]]
> 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="_maxrow_ge"
> 

                                <![CDATA[ 

                                maxrow >= #_maxrow_ge# 

                        ]]> 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="_maxrow_lt"
> 

                                <![CDATA[ 

                                maxrow 
<
 #_maxrow_lt# 

                        ]]
> 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="_start_ge"
> 

                                <![CDATA[ 

                                start >= #_start_ge# 

                        ]]> 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="_start_lt"
> 

                                <![CDATA[ 

                                start 
<
 #_start_lt# 

                        ]]
> 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="pagereg"
> 

                                pagereg like '%$pagereg$%' 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="kind"
> 

                                kind = #kind# 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="mapname"
> 

                                mapname = #mapname# 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="replaceb"
> 

                                replaceb = #replaceb# 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="replacea"
> 

                                replacea = #replacea# 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="ifredo"
> 

                                ifredo = #ifredo# 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="fenbianlv"
> 

                                fenbianlv = #fenbianlv# 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="_size_ge"
> 

                                <![CDATA[ 

                                size >= #_size_ge# 

                        ]]> 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="_size_lt"
> 

                                <![CDATA[ 

                                size 
<
 #_size_lt# 

                        ]]
> 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="remark"
> 

                                remark like '%$remark$%' 

                        
</
isNotEmpty
> 

                        
<
isNotEmpty 
prepend
="and" 
property
="status"
> 

                                status = #status# 

                        
</
isNotEmpty
> 

                
</
dynamic
> 

                
<
dynamic prepend=""
> 

                        
<
isNotNull 
property
="_start"
> 

                                
<
isNotNull 
property
="_size"
> 

                                        limit #_start#, #_size# 

                                
</
isNotNull
> 

                        
</
isNotNull
> 

                
</
dynamic
> 

        
</
sql
> 

        
<
select 
id
="findByParamsForCount" 
parameterClass
="map" 
resultClass
="int"
> 

                
<
include 
refid
="sql_count"
/> 

                
<
include 
refid
="sql_where"
/> 

        
</
select
> 

        
<
select 
id
="findByParams" 
parameterClass
="map" 
resultMap
="channel.result"
> 

                
<
include 
refid
="sql_select"
/> 

                
<
include 
refid
="sql_where"
/> 

        
</
select
>
 
通过上面的映射,我们可以很清楚的看到,SQL的片段得到了重用,分页很优雅,统计和全功能查询也非常强大,相比hibernate,有过之而无不及,当然如果你不会这么用,那就麻烦多了。
 
9、我认为,iBatis应该尽量使用单表增删改差业务来组合功能更为强大的业务操作。但并不排斥使用多表关联进行查询,多表关联查询,结果集往往需要定义新的JavaBean来进行存储,但也可以简单的返回一个Map来存储结果集。
        <!--
 动态条件分页查询 --> 

        
<
sql 
id
="sql_count"
> 

                select count(a.*) 

        
</
sql
> 

        
<
sql 
id
="sql_select"
> 

                select a.id                vid, 

                a.img             imgurl, 

                a.img_s         imgfile, 

                b.vfilename vfilename, 

                c.id                sid, 

                c.url             url, 

                c.filename    filename, 

                c.status        status 

        
</
sql
> 

        
<
sql 
id
="sql_where"
> 

                From secfiles c, juji b, videoinfo a 

                where 

                a.id = b. videoid 

                and b.id = c.segmentid 

                and c.status = 0 

                
<
dynamic prepend=""
> 

                        
<
isNotNull 
property
="_start"
> 

                                
<
isNotNull 
property
="_size"
> 

                                        limit #_start#, #_size# 

                                
</
isNotNull
> 

                        
</
isNotNull
> 

                
</
dynamic
> 

        
</
sql
> 

        <!--
 返回没有下载的记录总数 --> 

        
<
select 
id
="getUndownFilesForCount" 
parameterClass
="map" 
resultClass
="int"
> 

                
<
include 
refid
="sql_count"
/> 

                
<
include 
refid
="sql_where"
/> 

        
</
select
> 

        <!--
 返回没有下载的记录 --> 

        
<
select 
id
="getUndownFiles" 
parameterClass
="map" 
resultClass
="java.util.HashMap"
> 

                
<
include 
refid
="sql_select"
/> 

                
<
include 
refid
="sql_where"
/> 

        
</
select
>
 
在上面,我们的结果集返回为resultClass="java.util.HashMap",这时候,需要根据字
段的名称来取值,值类型为Object,key类型为String,这点要注意了:
        
public List<Map<String,Object>> findUndownFiles(Map map) { 

                
return getSqlMapClientTemplate().queryForList(
"secfiles.getUndownFiles", map); 

        }
 
        
public 
void test_findUndownFiles() { 

                List<Map<String, Object>> co = ser.findUndownFiles(
new HashMap()); 

                StringBuilder s = 
new StringBuilder(); 

                
for (Map<String, Object> map : co) { 

                        System.out.println(
"---------------------------"); 

                        
for (Map.Entry<String, Object> entry : map.entrySet()) { 

                                System.out.print(entry.getKey()+
"\t"); 

                                System.out.println(entry.getValue()); 

                        } 

                } 

        }
 
打印结果:
--------------------------- 

sid  1 

vfilename  200905252009235799 

url  http://d18.v.iask.com/f/1/f47817a394730dc682e660b943e84cc41006606.flv 

status  0 

filename  200905252009235799-00.flv 

imgfile  200905252009234399.jpg 

vid  1 

imgurl  http://p4.v.iask.com/95/595/1757503_1.jpg 

--------------------------- 

sid  2130 

vfilename  2009062615063867492 

url  http://lz.dhot.v.iask.com/f/1/0ee2ae8b973988f6a93c071c8045ca5217266409.mp4 

status  0 

filename  2009062615063867492-00.mp4 

imgfile  2009062615063825434.jpg 

vid  93 

imgurl  http://cache.mars.sina.com.cn/nd/movievideo//thumb/2/1502_120160.jpg 

--------------------------- 

sid  2131 

vfilename  2009062615064184076 

url  http://lz5.dhot.v.iask.com/f/1/36d3dadacb8d6bda434a58e7418ad3cc19037464.flv 

status  0 

filename  2009062615064184076-00.flv 

imgfile  2009062615064136733.jpg 

vid  94 

imgurl  
 
10、iBatis在开发效率上并没有比Hibernate差,如果你觉得太难用,那说明你还不够精,两者各有优缺点,应该扬长避短,最终发现:好东西都很简单!希望在这篇文章能为iBatis正名。
 
本文转自 leizhimin 51CTO博客,原文链接:http://blog.51cto.com/lavasoft/170160,如需转载请自行联系原作者
你可能感兴趣的文章
工作的准备:atoi,itoa,strcpy,memcpy,strcmp,二分查找,strcat
查看>>
Android 在闹钟开机时,如何解决开机动画没有播完就进入Launcher M
查看>>
2014第11周三
查看>>
jQuery File Upload跨域上传
查看>>
重构第27天 去除上帝类(Remove God Classes)
查看>>
用 Hexo + Next + GitHubPages 搭建漂亮的免费博客
查看>>
近期暴涨的BCH前景利好还是利空?未来能否撼动龙头老大的地位?
查看>>
少侠,留步,图片预览术
查看>>
304与缓存
查看>>
前端面试题-display:none和visibility:hidden的区别
查看>>
ES6小记
查看>>
Vue.js源码学习三 —— 事件 Event 学习
查看>>
vscode编辑器
查看>>
nuxt element-ui 上cdn
查看>>
利用K8S技术栈打造个人私有云(连载之:K8S环境理解和练手)
查看>>
学习笔记CB004:提问、检索、回答、NLPIR
查看>>
Android性能优化之UI实战
查看>>
Facebook Docusaurus 中文文档 siteConfig.js 详解
查看>>
iMooc-张鑫旭 CSS
查看>>
后台管理系统相关
查看>>