iBatis导读 ibaitis 级联查询
来源:互联网 发布:php实战视频教程 编辑:程序博客网 时间:2024/06/05 16:35
使用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>
<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>
<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>
<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 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);
}
* 删除指定标识的一个栏目
*
* @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>
<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);
}
* 根据动态条件查询栏目
*
* @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 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>
<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);
}
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());
}
}
}
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
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正名。
- iBatis导读 ibaitis 级联查询
- ibatis学习 : xml配置 -- 级联查询
- ibatis使用resultMap处理级联查询
- ibatis的级联查询、resultmap和resultclass区别
- iBATIS实战-导读
- 级联查询
- Ibaitis Caused by: com.ibatis.common.beans.ProbeException: Error getting ordinal list from JavaBean.
- 求解决,ibatis级联查询异常,求解决,哪里配置错了吗??(已经解决)
- ibaitis简介
- ibaitis实例
- iBatis 查询
- ORACLE级联查询
- 级联查询sql
- subsonic 级联查询
- 关于级联查询
- Creator(级联查询)
- Hibernate QBE 级联查询
- EOS的级联查询
- 延迟任务和周期任务的实现(ScheduledThreadPoolExecutor)
- MTP 与MSC 在FS上修改点
- 与监控有关的开源项目汇总
- ifconfig、ifup、ifdown
- 如何开机自启动程序
- iBatis导读 ibaitis 级联查询
- 松开手,你可以拥有更多
- shell 脚本 常用总结
- ios之在view中添加视图对象
- 如何用公式在LINKEY OA的表单管理中实现对字段的编辑控制
- 消息响应机制
- 13个Web前端开发框架
- 得到div在body中所在的绝对坐标和相对坐标
- windows下Perl的HelloWorld