首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

常识总结

2012-10-16 
知识总结Ibatis与其他ORM的不同IBATIS is built on the idea of mapping SQL to objects, not mapping dat

知识总结
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策略,实现与具体底层数据库的分离

热点排行