ibatis高级特性.docx
《ibatis高级特性.docx》由会员分享,可在线阅读,更多相关《ibatis高级特性.docx(18页珍藏版)》请在冰豆网上搜索。
ibatis高级特性
iBATIS高级特性
1、主要内容
●关联对象
●事务
●延迟加载
●缓存
●动态标签
●读写CLOB和BLOB字段
●与spring的整合
2、关联对象
我们的大部分员工习惯了Hibernate的关联对象查询、级联删除、级联保存等特性,那么iBATIS是否提供同样的功能呢?
这是大部分人会关心的内容。
答案也许是另人失望的。
iBATIS可以关联查询,却没有提供级联保存和级联删除的特性。
下面我们介绍如何处理关联对象之间的查询、保存及删除问题。
2.1关联查询
iBatis为我们提供了两种方式关联查询,第一种N+1次查询,第二种新支持的查询方式。
两种方式需要根据具体的应用环境,作出合适的选择。
前一种由于多了一次和数据库的读取操作,所以读取速度慢了些,但是可以使用延迟加载减少内存的消耗。
而后一种方式多了些内存消耗,但是读取速度要快了。
定义一个需求:
我们在查询订单的同时希望查询出其关联的订单项。
2.2.1采用N+1次查询
首先看看我们的SQLMapped配置文件如何配置的:
我们可以看到,RESULT的select属性指向一个新的查询语句。
说明:
这个很好的解决了关联查询的问题,而且如果我们配置了全局的延迟加载,当真正用到订单项的时候,iBatis才为我们做查询的动作。
但是这却带来了另外一个问题,N+1次查询的问题。
也就是多了一次数据库的读操作,有一定的性能损失。
2.2.2新查询方式
首先看看我们的SQLMapped配置文件如何配置的:
我们可以看到,RESULT的resultMap属性指向一个resultMap标签定义。
说明:
与前面N+1次查询方式比较,由于只读取数据库一次,的确读取速度更快了,但是由于存在更多的内存消耗(N+1方式可以通过延迟加载来减少内存的消耗),所以我们该根据具体的应用情况而选择合适的方式。
2.2级联保存
在Hibernate中,我们可以使用级联保存,而iBATIS并没有提供该功能特性,此时我们需要自己保存关联的对象数据。
定义一个需求:
在保存订单的时候,希望一起保存其关联的订单项。
其DAO层可以定义如下两个方法分别保存订单和关联的订单项:
BMO层可以作如下调用:
这里涉及到的事务等后面讲解事务的时候再说明如何实现。
2.3级联删除
同样iBatis未提供级连删除的特性,我们要删除连关联表一起删除,也需要自己实现,其方式和保存类似,第一次删除关联的子表如订单项,再删除其主表如订单。
3、事务
3.1自动事务
所谓自己事务,就是说IbatisAPI单个方法自动划分为一个事务,不需要显示的开始、提交、结束。
3.2局部事务
其主要针对一种应用程序、一个资源、且一次只能处理一个事务。
如图:
其配置如下:
实现方式:
说明:
在Spring已经使用AOP申明式事务,所以像上面的配置文件及编码式事务使用到的可能性不大。
在蓝本工程的bss-BluePrint-spring-db.xml其Spring配置如下:
只要SMOImpl匹配的类,其insert*、update*、add*、del*将自动使用事务。
3.3全局事务
全局事务定义了一个更大的事务范围,它可以夸数据库、消息队列、甚至包含其它应用程序。
下图展示了一个全局的事务系统:
下图展示一个全局事务的配置方式:
接口和iBATIS的局部事务相同。
这样当需要从局部事务切换到全局事务的时候会很方方便,只要更改配置文件,不需要更改接口代码了。
4、延迟加载
配置方式如下图:
该属性默认值为true,若该属性值为true,当采用N+1次查询的时候,iBatis会在需要关联数据的时候才开始执行查询。
5、缓存
6、动态标签
主要分为五类动态标签:
6.1dynamic标签
Dynamic可以使用的属性如下:
属性
功能
Prepend(可选)
该值作为前缀添加到标签的结果内容提前。
但是当标签的结果内容体为空的时候,prpend值将不其作用。
Open(可选)
该值作为前缀添加到标签的结果内容提前。
如果结果内容体为空的时候,open值将不被附加到其前面。
Open值将在prepend属性值被添加到前缀之前先被添加前缀。
例如假设prepend=”when”,而open=”(”,则最终得到的组合是”when(“。
Close(可选)
该值作为后缀添加到标签的结果内容提后。
如果标签的结果内容体为空的时候,close值将不起作用。
使用示例如下:
6.2二元标签
二元标签的属性如下:
属性
功能
Property(必选)
参数对象用于同compareProperty或compareValye作比较的特性
Prepend(可选)
该值作为前缀添加到标签的结果内容提前。
但是当标签的结果内容体为空的时候,prpend值将不其作用。
Open(可选)
该值作为前缀添加到标签的结果内容提前。
如果结果内容体为空的时候,open值将不被附加到其前面。
Open值将在prepend属性值被添加到前缀之前先被添加前缀。
例如假设prepend=”when”,而open=”(”,则最终得到的组合是”when(“。
Close(可选)
该值作为后缀添加到标签的结果内容提后。
如果标签的结果内容体为空的时候,close值将不起作用。
romoveFirstPrepend(可选)
该值用于决定第一个嵌套的内容生成标签是否有移除其prepend值
compareProperty、compareValye(两个必有其一)
用来同property特性值作比较
二元动态标签如下:
Property属性与compareProperty或pareValye属性值作比较,看是否相同
Property属性与compareProperty或pareValye属性值作比较,看是否不同
Property属性是否大于pareProperty或pareValye属性值
Property属性与compareProperty或pareValye属性值作比较,看是否相同
Property属性与compareProperty或pareValye属性值作比较,看是否相同
Property属性与compareProperty或pareValye属性值作比较,看是否相同
使用示例如下:
6.3一元标签
一元标签的属性如下:
属性
功能
Property(必选)
参数对象用于同compareProperty或compareValye作比较的特性
Prepend(可选)
该值作为前缀添加到标签的结果内容提前。
但是当标签的结果内容体为空的时候,prpend值将不其作用。
Open(可选)
该值作为前缀添加到标签的结果内容提前。
如果结果内容体为空的时候,open值将不被附加到其前面。
Open值将在prepend属性值被添加到前缀之前先被添加前缀。
例如假设prepend=”when”,而open=”(”,则最终得到的组合是”when(“。
Close(可选)
该值作为后缀添加到标签的结果内容提后。
如果标签的结果内容体为空的时候,close值将不起作用。
romoveFirstPrepend(可选)
该值用于决定第一个嵌套的内容生成标签是否有移除其prepend值
一元标签如下:
确定参数对象中是否存在所指定的字段。
对于bean,它寻找一个特性;对象map,它寻找一个键。
确定参数对象中是否不存在所指定的字段。
对于bean,它寻找一个特性;对象map,它寻找一个键。
确定参数对象中是否为空。
对于bean,它寻找一个特性;对象map,它寻找一个键。
确定参数对象中是否不为空。
对于bean,它寻找一个特性;对象map,它寻找一个键。
确定参数对象中是否为空、空字符串、空集合或空的String.valueOf().
确定参数对象中是否为非空、非空字符串、非空集合或非空的String.valueOf().
使用示例如下:
6.4参数标签
参数标签的属性如下:
属性
功能
Prepend(可选)
该值作为前缀添加到标签的结果内容提前。
但是当标签的结果内容体为空的时候,prpend值将不其作用。
Open(可选)
该值作为前缀添加到标签的结果内容提前。
如果结果内容体为空的时候,open值将不被附加到其前面。
Open值将在prepend属性值被添加到前缀之前先被添加前缀。
例如假设prepend=”when”,而open=”(”,则最终得到的组合是”when(“。
Close(可选)
该值作为后缀添加到标签的结果内容提后。
如果标签的结果内容体为空的时候,close值将不起作用。
romoveFirstPrepend(可选)
该值用于决定第一个嵌套的内容生成标签是否有移除其prepend值
参数标签如下:
标签
说明
确定参数对象是否存在
确定参数对象是否不存在
使用示例如下:
6.5
iterate标签的属性如下:
属性
功能
Property(必选)
参数对象用于同compareProperty或compareValye作比较的特性
Prepend(可选)
该值作为前缀添加到标签的结果内容提前。
但是当标签的结果内容体为空的时候,prpend值将不其作用。
Open(可选)
该值作为前缀添加到标签的结果内容提前。
如果结果内容体为空的时候,open值将不被附加到其前面。
Open值将在prepend属性值被添加到前缀之前先被添加前缀。
例如假设prepend=”when”,而open=”(”,则最终得到的组合是”when(“。
Close(可选)
该值作为后缀添加到标签的结果内容提后。
如果标签的结果内容体为空的时候,close值将不起作用。
Conjunction(可选)
连接遍历集合(数组)时重复产生的那些SQL片段
romoveFirstPrepend(可选)
该值用于决定第一个嵌套的内容生成标签是否有移除其prepend值
使用示例如下:
7、读取CLOB和BLOB字段
在使用Oracle数据库时,读取CLOB和BLOB等大类型的数据一直是个比较犯难的事,一般都是通过JDBC代码来实现对CLOB和BLOB数据的读写,效果和性能都是最好的,但是代码也相当复杂,且代码难以重用。
7.1使用Spring的OracleLobHandler类处理
采用这种方法只对数据源是直接连接Oracle的JDBC驱动方式有效,如果你采用数据连接池作为数据源,则这种办法无效。
根据我们公司的BSS3.0的情况使用可能性不大。
所以这里不作介绍了。
7.2实现Ibatis的TypeHandlerCallback接口
sqlMap的配置如下:
说明:
通过实现ibatis的回调接口来实现,也有一定的局限性,需要新增一个类,配置也不方便,还可能会出错。
7.3通过配置ParameterMap和ResultMap来实现对LOB类型的读写
说明:
这样测试后发现也有其超过了4000个字符就不能插入,而CLOB类型的字段可以存4GB大小的字符。
这里只说了CLOB如何去实现,BLOB实现方式是一样的,只要注意其javaType既JAVA类型。
如下所示:
8、与Spring的整合
核心配置方法如下:
DAO实现方式:
说明:
只需要继承SqlMapClientDaoSupport,利用该类的提供
getSqlMapClientTemplate方法获取所需要的模板类,其接口方法和我们iBatis的SqlMapClient方法基本相同。
附件:
1、关于ibatis缓存
在你的xml配置文件中,每一个 cacheModel 元素,如下
(1)、 属性readOnly如果不写,默认是true,这时的缓存效果无疑最好,因为系统不需要考虑更新操作引起缓存与实际数据不一致的问题,只读缓存的例子是固化到数据库中的一些配置参数表。
但是,通常我们想缓存的数据是需要增删改的,这时务必记得要加上 readOnly = false;
(2)、属性serialize,如果不写,默认为false, 将它设为true,可以提高整体应用(而不仅仅是每个Session)的性能。
这种缓存为每一个Session返回缓存对象不同的实例(复本)。
因此每一个Session都可以安全修改返回的对象. 注意,此时readOnly必须为false。
如果你把它设为 true ,记得检查两件事,一件事是缓存中存放的对象(你想查询的POJO)必须是可序列化的, 即实现Serializable接口。
如果你有一个复杂对象属性,它也必须满足这个规则,你的整个对象树必须是可序列化的。
另一件事是关闭sql-map-config中的延迟加载属性,即lazyload=false,原因是,它使用了动态代理机制, 那个代理对象并不是Serializable的。
缓存类型的最佳适应情形:
MEMORY 没有统一的对象重用模式的应用,或内存不足的应用。
LRU 在较长的期间内,用户经常使用某些特定对象。
FIFO 用户在短时间内持续引用特定的查询,而后很可能不再使用。
根据个人实践,内存充足时使用LRU,否则使用MEMORY(WEAK)通常能获得较好的效果。