ibaitis 级联查询

使用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   http://cache.mars.sina.com.cn/nd/movievideo//thumb/6/2106_120160.jpg
 

你可能感兴趣的:(sql,Hibernate,ibatis,jdbc,C#)