`
阅读更多
Ibatis与其他ORM的不同
IBATIS is built on the idea of mapping SQL to objects, not mapping database tables to objects.


注意!大多数JDBC Driver只有在字段可以为NULL时需要指定jdbcType属性。因此,对于这些Driver,只是在字段可以为NULL
时才需要指定type属性。
注意!当使用Oracle Driver时,如果没有给可以为NULL的字段指定jdbcType属性,当试图给这些字段赋值NULL时,会出现"
Invalid column type"错误。
而JDBC的接口中,关于Null的设置,是方法setNull(parameterIndex, sqlType),所以是需要指定sqlType(列数据类型)的。


注意!在内嵌参数中,要指定NULL的替代值,必须要先指定数据类型。如#description:VARCHAR:NO_ENTRY#
注意!如需要在查询时也使用NULL替代值,必须同时在resultMap中定义(如下说明)。
注意!如果您需要指定很多的数据类型和NULL替代值,可以使用外部的parameterMap元素,这样会使代码更清晰。

注意!ResultSet的列值按它们在resultMap中定义的顺序读取(这特性会在某些实现得不是很好的JDBC Driver中派上用场)。


jdbcType有时是必要的,比如对于java类型的Date,数据库可能有3种对应类型,date, time, timestamp(datetime),那么就有
必要指定jdbcType了,应为PrepareStatement有setDate,setTime,setTimestamp 3个方法(jdbcType取值为java.sql.Types中定义的常量名)


记住,如果您要在查询和更新中同样使用nullValue功能,必须同时在parameterMap中指定nullValue属性。否则查询出来的null
值替换为nullValue到对象中,随后更新时会将这个nullValue更新到数据库,所以也需要在更新中设置这个nullValue值,以便将
这个字段仍然设置为null

基本的原则是,如果您需要访问相关的对象,则使用联合查询。否则,使用延迟加载和字节码增强选项的子查询。
如果您要缓存查询结果,则使用子查询(而不是联合查询)来缓存查询结果。

如果使用微软的SQL Server 2000 JDBC驱动程序,为了在手工事务模式中执行多条语句,需要在数据库连接url加上SelectMethod
=Cursor。

对于SqlMapClient.queryForObject(String id, Object parameterObject, Object resultObject)接口,可以用于多次查询构造
结构的情况,其中参数resultObject是程序中实例化的对象,传入多次查询操作中用于联合构造想要的结果。

[Important!] Currently the SQL Map framework does not automatically resolve circular relationships. Be
aware of this when implementing parent/child relationships (trees). An easy workaround is to simply define
a second result map for one of the cases that does not load the parent object (or vice versa), or use a join as
described in the “N+1 avoidance” solutions.

有些sql中的部分,不能作为PreparedStatement的参数部分,所以只能使用$variable_name$来进行简单的字符串替换,然后将替换
的字符串作为PrepareStatement的语句。

【注意!】ibatis的session是绑定到Thread级别的,不同的Thread会产生不同的session.

对于ibatis缓存的理解:
readOnly属性:标识对于不同的session,cache如何返回缓存对象,如果readOnly=true,则不同的session返回相同的shared
object(适合缓存只读的数据,否则不同session会访问到其他session正在修改的数据,显然会造成数据不一致)
,而readOnly=false,则对于不同的session scope(同一线程中不同的事务存在不同的session scope)返回不同
的实例[具体实现也和serialize的取值有关,若为false,则每个session(transaction level) scope都需要从新
查询数据放入缓存,若serialize为true,则只需要查询一次放入缓存,之后每次都是deep copy].
serialize: 标识从缓存中取出对象时,取出的皆为缓存对象的深层拷贝(deep copy),这就要求整个对象图(object graph)中
涉及的类都是serializable的,所以不能使用lazy-loading(需要在sql-map-config的setting中设置为false),因
为lazy-loading生成的proxy对象没有实现serializable接口,无法深层拷贝;

cache的key涉及到多个部分,大体说是和相应statement对象有关的,不同statement定义,即使sql和参数都相同,也是不相关的,假设配置为同一个cacheModel,他们的cache key也不会重叠(不会有相同);

readOnly(true) + serialize(false) = Good, 适用于只读数据的缓存,获取到各session的shared cached object,因为不修改,
所以安全,强调'所有'session scope'共享'该缓存;
readOnly(false) + serialize(true) = Good, 适用于读写数据的缓存,每次从缓存获取对象都是deep copied object,所以可以
安全的进行修改并更新,注意涉及到的更新都需要配置到缓存的<flushOnExecute>中;
readOnly(false) + serialize(false) = Caution, 查看readOnly与serialize属性解释可以得出,这种搭配适用于session(trans-
action level) scope内的复用,每次session scope开始时,查询一次数据库获取数据放入cache中(此时cache key中
包含session scope组成部分),然后在该session scope剩余部分中享用,这种搭配适用场景比较少;
readOnly(true) + serialize(true) = Bad, 不推荐,原则上同readOnly(false) + serialize(true)意义相同,但既然是readOnly
=true,那deep copy又有何用,deep copy用来只读的数据是多余的;
注意Cache中的ReadOnly(只读)并非指该缓存数据不能修改,实际上是可以修改的,但是如果修改就会产生数据完整性错误,所以是禁
止修改的,但是缓存数据也并非不能改变的,<flushOnExecute>照样是适用的,即发生某些更新操作时需要清空缓存,以便重新缓存。<flushInterval/>即间隔多长时间清空缓存数据,以便重新缓存。
而对于ReadOnly为false的数据,可以进行属性修改(如为了前端显示等)。
所以从只读缓存中拿出来的实体对象不能直接更改属性然后调用update statement保存,因为这些对象是各个session之间共享的,但
读写缓存则可以,他们是不同的实例,前者可以通过从新构造一个对象,然后把状态拷贝过去修改然后调用update statement更新,并
flush cache。
基于上述,可以看出,cache的配置很灵活,并非只读缓存就一定使用ReadOnly=true,读写缓存也可以使用ReadOnly=true,比如只可
能有一个session同时修改缓存数据,并且该缓存数据的用户(读取客户)对于数据一致性不关切时。


lob字段的处理,枚举字段的实现(枚举ibatis-2.3.4.726已经支持,见TypeHandlerFactory;lob在spring中已经提供相应的TypeHandler支持,分别为BlobByteArrayTypeHandler和ClobStringTypeHandler)
分页的实现,queryForList(statementName, skipResults, maxResults)默认是使用resultset滚动,但可以扩展为使用数据库的物理分页功能(sql如limit等),配以Dialect策略,实现与具体底层数据库的分离
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics