iBatis相关总结

一,iBatis简介

相对Hibernate和Apache OJB 等“一站式”ORM(对象关系映射 Object Relational Mapping,简称ORM)解决方案而言,ibatis 是一种“半自动化”的ORM实现。

纵观目前主流的ORM,无论Hibernate 还是Apache OJB,都对数据库结构提供了较为完整的封装,提供了从POJO 到数据库表的全套映射机制,程序员往往只需定义好了POJO 到数据库表的映射关系,即可通过Hibernate或者OJB 提供的方法完成持久层操作,可以说是“一站式”的服务,程序员甚至不需要对SQL 的熟练掌握。但是当遇到这样的情况时Hibernate就显得没有那么好用了

1. 系统的部分或全部数据来自现有数据库,处于安全考虑,只对开发团队提供几条Select SQL(或存储过程)以获取所需数据,具体的表结构不予公开。
2. 系统数据处理量巨大,性能要求高,需要高度优化的SQL语句才能达到系统性能要求。

3. IBatis相较于Hibernate比较容易上手,掌握。

“半自动化”的ibatis,却刚好解决了这个问题。这里的“半自动化”,是相对Hibernate等提供了全面的数据库封装机制的“全自动化”ORM 实现而言,“全自动”ORM 实现了POJO 和数据库表之间的映射,以及SQL 的自动生成和执行。而ibatis 的着力点,则在于POJO 与SQL之间的映射关系。也就是说,ibatis并不会为程序员在运行期自动生成SQL 执行。具体的SQL 需要程序员编写,然后通过映射配置文件,将SQL所需的参数,以及返回的结果字段映射到指定POJO。

总结:Hibernate对ORM提供了“一站式,全自动”的封装,实现了POJO和数据库表之间的映射,程序员可以不用编写具体的sql语句,也能完成持久层的操作,但是不够灵活。iBatis实现了POJO和sql语句的映射,通过映射配置文件,将SQL所需的参数,以及返回的结果字段映射到指定POJO。所以需要程序员编写具体的sql语句,但是也较灵活,效率更高。

二,具体运用(与spring结合使用)

1 、导入ibatis相关的jar 包,ibatis-2.3.0.677.jar 、mysql-connector-java-5.1.6-bin.jar

2、spring加载ibatis相关xm配置l文件SqlMapClinetFactory.xml


 

    
        
        
        
    
      


      

      
          
      
    
3、sql-map-config.xml文件





    
            

相关节点

参数
描述
cacheModelsEnabled
是否启用 SqlMapClient 上的缓存机制。
建议设为 "true"
enhancementEnabled
是否针对 POJO 启用字节码增强机制以提升
getter/setter 的调用效能,避免使用 Java
Reflect 所带来的性能开销。
同时,这也为 Lazy Loading 带来了极大的性能
提升。
建议设为 "true"
errorTracingEnabled
是否启用错误日志,在开发期间建议设为 "true"
以方便调试
lazyLoadingEnabled
是否启用延迟加载机制,建议设为 "true"
maxRequests
最大并发请求数( Statement 并发数)
maxTransactions
最大并发事务数
maxSessions
最大 Session 数。即当前最大允许的并发 SqlMapClient 数。
maxSessions 设定必须介于
maxTransactions maxRequests 之间,即
maxTransactions
maxRequests
useStatementNamespaces
是否使用 Statement 命名空间。
这里的命名空间指的是映射文件中, sqlMap 节点
namespace 属性,如在上例中针对 t_user
表的映射文件 sqlMap 节点:
< sqlMap namespace = "User" >
这里,指定了此 sqlMap 节点下定义的操作均从
属于 "User" 命名空间。
useStatementNamespaces= "true" 的情
况下, Statement 调用需追加命名空间,如: sqlMap.update( "User.updateUser" ,use
r);
否则直接通过 Statement 名称调用即可,如:
sqlMap.update( "updateUser" ,user);
但请注意此时需要保证所有映射文件中,
Statement 定义无重名。
4,具体映射配置文件





    
	
	
	 
    
   
   
    
  
  
  
  
       update customer set 
           name=#name#
          ,address=#address#
        where customer_id=$customer_id$
    

以update节点为例:
⑴ ID
指定了操作ID,之后我们可以在代码中通过指定操作id 来执行此节点所定义的操作,如:
this.getSqlMapClient().update("customer.update", customer);
ID设定使得在一个配置文件中定义两个同名节点成为可能(两个update节点,以不同id区分)

⑵ parameterClass
指 定 了操作所需的参数类型, 此例中update 操作以com.remote3c.bean.Customer类型的对象作为参数,目标是将提供的Customer实例更新到数据库。parameterClass="customer"中,customer为“com.remote3c.bean.Customerr”类的别名,别名可通过typeAlias节点指定,如示例配置文件中的:


通过节点,可以避免SQL 中与XML 规范相冲突的字符对XML映射文件的合法性造成影响。在sql语句中有大于小于符合“> <”时要使用这个节点,否则会报错。
(4) SQL中所需的用户名参数,“#name#”在运行期会由传入的user对象的name属性自动填充。
(5) SQL 中所需的用户性别参数“#sex#”,将在运行期由传入的user 对象的sex属性自动填充。
(6) SQL中所需的条件参数“#id#”,将在运行期由传入的user对象的id属性填充。
(7)#和$的区别

1,

$ 的作用实际上是字符串拼接,


select * from $tableName$ 
等效于 
StringBuffer sb = new StringBuffer(256); 
sb.append("select * from ").append(tableName); 
sb.toString(); 
结果 :select  * from user;
如果这里用#tanbleName#,结果会变成这个样子 select * from 'user';
2,
#用于变量替换 
select * from table where id = #id# 
等效于 
prepareStement = stmt.createPrepareStement("select * from table where id = ?") 
prepareStement.setString(1,'abc'); 
结果就是 select  * from table where id ='abc';
3,一般传参数能用#的就别用$. 直观的说 
#str# 出来的效果是  'str' 
$str$ 出来的效果是  str
如果字段类型为字符串,则必须使用#str# 传参,使用$str$会报错。
4,#能防止sql注入。

三、高级特性

1、一对多的关联

在实际开发中,我们常常遇到关联数据的情况,如User 对象拥有若干Address 对象,每个Address 对象描述了对应User 的一个联系地址,这种情况下,我们应该如何处理?通过单独的Statement操作固然可以实现(通过Statement 用于读取用户数据,再手
工调用另外一个Statement 根据用户ID 返回对应的Address信息)。不过这样未免失之繁琐。下面我们就看看在ibatis 中,如何对关联数据进行操作。ibatis 中,提供了Statement 嵌套支持,通过Statement 嵌套,我们即可实现关联数据的操作。

下面的例子中,我们首选读取t_user 表中的所有用户记录,然后获取每个用户对应的所有地址信息。
配置文件如下:




 
     
     
     
     
 
 
 


result常见的有两种类型,resultClass和resultMap,这里通过在resultMap 中定义嵌套查询getAddressByUserId,我们实现了关联数据的读取。实际上,这种方式类似于前面所说的通过两条单独的Statement 进行关联数据的读取,只是将关联关系在配置中加以描述,由ibatis自动完成关联数据的读取。
需要注意的是,这里有一个潜在的性能问题,也就是所谓“n+1”Select问题。,假设t_user 表中有十万条记录,那么这样的操作将需要100000+1 条Select语句反复执行才能获得结果,无疑,随着记录的增长,这样的开销将无法承受。
2、动态的映射查询条件

      
这表明对通过id为"getUser"的Select statement获取的数据,使用cacheModel "userCache"进行缓存。之后如果程序再次用此Statement进行数据查询,即直接从缓存中读取查询结果,而无需再去数据库查询。
cacheModel主要有下面几个配置点:
*  flushInterval :设定缓存有效期,如果超过此设定值,则将此CacheModel的缓存清空。
*size:本CacheModel中最大容纳的数据对象数量。
*flushOnExecute:指定执行特定Statement时,将缓存清空。如updateUser操作将更新数据库中的用户信息,这将导致缓存中的数据对象与数据库中的实际数据发生偏差,因此必须将缓存清空以避免脏数据的出现

高级一点的属性

结合cacheModel来看:


可以看到,Cache有如下几个比较重要的属性:
Ø readOnly
Ø serialize
Ø type

readOnly
readOnly值的是缓存中的数据对象是否只读。这里的只读并不是意味着数据对象一旦放入缓存中就无法再对数据进行修改。而是当数据对象发生变化的时候,如数据对
象的某个属性发生了变化,则此数据对象就将被从缓存中废除,下次需要重新从数据库读取数据,构造新的数据对象。而 readOnly="false"则意味着缓存中的数据对象可更新,如user 对象的name属性发生改变。只读Cache能提供更高的读取性能,但一旦数据发生改变,则效率降低。系统设计时需根据系统的实际情况(数据发生更新的概率有多大)来决定Cache的读写策略。

serialize
如果需要全局的数据缓存,CacheModel的serialize属性必须被设为true。否则数据缓存只对当前Session(可简单理解为当前线程)有效,局部缓存对系统的整体性能提
升有限。在 serialize="true"的情况下,如果有多个Session同时从Cache 中读取某个数据对象,Cache 将为每个Session返回一个对象的复本,也就是说,每个Session 将
得到包含相同信息的不同对象实例。因而Session 可以对其从Cache 获得的数据进行存取而无需担心多线程并发情况下的同步冲突。

Cache Type:
与hibernate类似,ibatis通过缓冲接口的插件式实现,提供了多种Cache的实现机
制可供选择:
1.LRU  --当Cache达到预先设定的最大容量时,ibatis会按照“最少使用”原则将使用频率最少的对象从缓冲中清除
2.FIFO  --先进先出型缓存,最先放入Cache中的数据将被最先废除。可配置参数与LRU型相同
3.OSCACHE  --与上面几种类型的Cache不同,OSCache来自第三方组织Opensymphony。


你可能感兴趣的:(iBatis相关总结)