`

闲话iBatis

阅读更多
使用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
 
10、iBatis在开发效率上并没有比Hibernate差,如果你觉得太难用,那说明你还不够精,两者各有优缺点,应该扬长避短,最终发现:好东西都很简单!希望在这篇文章能为iBatis正名。
分享到:
评论
1 楼 宋双旺 2013-02-21  
似乎最后没有贡献代码生成工具,呵呵

相关推荐

    ibatis总结 ibatis ibatis ibatis ibatis

    Ibatis 是一款轻量级的Java持久层框架,它允许开发者将SQL语句与Java代码分离,从而使得数据库访问更加灵活、易于维护。本篇文章将深入探讨Ibatis的核心概念、最佳实践以及与其他框架如Struts和Spring的整合。 1. ...

    ibatis demo,ibatis例子,ibatis示例

    Ibatis,全称为MyBatis,是一个优秀的Java持久层框架,它主要负责SQL映射,使得开发者能够将SQL语句与Java代码分离,从而更好地管理数据库操作。Ibatis的出现,解决了传统JDBC中手动编写SQL和结果集映射的繁琐工作,...

    ibatis源码,ibatis源码 ibatis源码 ibatis源码

    《深入解析iBatis源码》 iBatis,一个优秀的Java持久层框架,以其轻量级、灵活的特性在众多ORM(Object-Relational Mapping)框架中独树一帜。iBatis的核心在于它的SQL映射机制,它将数据库操作与业务逻辑解耦,...

    iBATIS-DAO-2.3.4.726.rar_com.ibatis.dao_iBATIS dao 2_iBatis DAO_

    iBATIS DAO是Java开发中的一个持久层框架,它提供了数据访问对象(DAO)的实现,使得数据库操作更加简单和灵活。在这个2.3.4.726版本的源码中,我们可以深入理解iBATIS DAO的工作原理,并通过添加注释来帮助我们更好...

    Ibatis入门例子,Ibatis教程

    Ibatis,全称为MyBatis,是一个优秀的Java持久层框架,它主要负责SQL映射,使得开发者能够将注意力集中在编写SQL语句上,而无需关注JDBC代码的编写。Ibatis消除了几乎所有的JDBC代码和手动设置参数以及获取结果集的...

    ibatis教程,ibatis帮助文档

    iBATIS是一个由Clinton Begin创建,目前由Apache基金会支持的持久化框架,它专注于数据库查询的简化,尤其在JDBC编程方面提供了极大的便利。相对于全自动化ORM解决方案如Hibernate,iBATIS被称为“半自动化”ORM实现...

    ibatis api,ibatis文档,ibatis说明文档

    Ibatis,全称为MyBatis,是一个优秀的Java持久层框架,它主要负责SQL映射,将数据库操作与业务逻辑解耦,使得开发者可以更专注于业务逻辑的实现,而无需关心繁琐的SQL语句编写。本篇文章将深入探讨Ibatis API、文档...

    Ibatis3手册 Ibatis3参考手册

    ### Ibatis3手册知识点概述 Ibatis3作为一款流行的持久层框架,在软件开发领域具有重要的地位。本篇文章基于“Ibatis3手册 Ibatis3参考手册”的标题及描述,深入解析Ibatis3的核心概念、架构特点以及如何进行实际...

    ibatis2指南及ibatis包

    ibatis2指南ibatis2指南ibatis2指南ibatis2指南ibatis2指南ibatis2指南ibatis2指南ibatis2指南ibatis2指南ibatis2指南ibatis2指南ibatis2指南ibatis2指南

    ibatis应对批量update

    ### ibatis应对批量update 在处理大量数据更新时,传统的for循环方式往往会导致效率低下。这是因为每一次循环都需要执行一次数据库连接操作,对于批量更新来说,这样的处理方式显然不够高效。为了解决这个问题,...

    iBatis开发指南和一个iBatis实例

    iBatis是一个轻量级的Java持久层框架,它提供了SQL映射框架,将SQL语句与Java代码分离,使得数据库访问更为灵活和可控。在本压缩包中,你将找到一系列关于iBatis的学习资源,包括PDF文档、实例代码等,这些都是深入...

    ibatis api 帮助文档+IBATIS 开发文档

    **IBATIS API 帮助文档与IBATIS开发文档详解** IBATIS,一个由iBATIS公司开发的开源持久层框架,是Java世界中广泛使用的数据访问接口(DAO)工具。它允许开发者将SQL语句直接写在XML配置文件中,实现了SQL与Java...

    Spring与iBATIS的集成

    Spring与iBATIS的集成 iBATIS似乎已远离众说纷纭的OR框架之列,通常人们对非常流行的Hibernate情有独钟。但正如Spring A Developer's Notebook作者Bruce Tate 和Justin Gehtland所说的那样,与其他的OR框架相比...

    iBATIS实战.pdf

    《iBATIS实战》是讲述iBATIS框架的权威著作。书中既详实地介绍了iBATIS的设计理念和基础知识,也讨论了动态SQL、高速缓存、DAD框架等高级主题,还讲解了iBATIS在实际开发中的应用。《iBATIS实战》的最后给出了一个...

    Ibatis

    **Ibatis 指南** Ibatis 是一个优秀的开源持久层框架,它允许开发者将 SQL 查询与 Java 代码分离,从而避免了传统的 JDBC 编程中的大量模板代码。作为一个轻量级的框架,Ibatis 提供了灵活的映射机制,使得 XML 或...

    Ibatis 入门经典 实例

    《Ibatis 入门经典 实例》 Ibatis 是一款著名的轻量级 Java 持久层框架,它提供了一种映射 SQL 和 Java 对象的简单方式,从而减轻了开发人员在数据库操作中的工作负担。这篇实例教程将带你深入理解 Ibatis 的核心...

    Spring+ibatis 保留ibatis事务的配置

    根据提供的文件信息,本文将详细解析如何在Spring与ibatis框架整合时,通过特定配置来保留ibatis事务处理机制,并实现对事务的自定义控制。文章将围绕标题、描述及部分代码片段展开讨论。 ### Spring与ibatis整合...

    ibatis乱码解决方法(ibatis独立)

    在IT行业中,数据库操作是必不可少的一部分,而Ibatis作为一款流行的Java持久层框架,它使得SQL与Java代码更好地结合,提供了灵活的数据库操作方式。然而,数据处理时遇到的编码问题,如乱码,常常会给开发者带来...

    C# IBatis IBatis基础 完整项目

    【标题】:“C# IBatis IBatis基础 完整项目” 【描述】中提到的是一个基于C#的IBatis学习项目,适用于初学者。IBatis是一个流行的数据访问层框架,它允许开发者将SQL语句与应用程序代码分离,提高了代码的可维护性...

    ibatisDemo 入门源码

    《IbatisDemo入门源码详解》 IbatisDemo是一个典型的基于Ibatis框架的入门示例,它为我们展示了如何在Java项目中使用Ibatis进行数据库操作。Ibatis,一个优秀的持久层框架,它允许开发者将SQL语句直接写在配置文件...

Global site tag (gtag.js) - Google Analytics