ibatis指南阅读笔记
 

2009-01-08 作者:zzg 来源:javaeye.com

 

半自动化的ibatis

ibatis并不会为程序员在运行期自动生成sql执行。具体的sql需要程序员编写,然后通过映射配置文件,将sql所需的参数,以及返回的结果字段映射到指定的pojo。

使用ibatis提供的ORM机制,对业务逻辑实现人员而言,面对的是纯粹的java对象,这一层与通过hibernate实现orm而言基本一致,而对于具体的数据操作,hibernate会自动生成sql语句,而ibatis则要求开发者编写具体的sql语句。

ibatis采用了apache common_logging,并结合了log4j作为日志输出组件。在classpath新建log4j.properties

xml 代码

  1. log4j.rootLogger=DEBUG, stdout  
  2. log4j.appender.stdout=org.apache.log4j.ConsoleAppender  
  3. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout  
  4. log4j.appender.stdout.layout.ConversionPattern=%c{1} - %m%n  
  5. log4j.logger.java.sql.PreparedStatement=DEBUG  

SqlMapConfig.xml代码

xml 代码  

  1. xml version="1.0" encoding="UTF-8" ?>   
  2.  
  3.                PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"    
  4.                "http://www.ibatis.com/dtd/sql-map-config-2.dtd">   
  5.  <sqlMapConfig>   
  6.      <settings  cacheModelsEnabled="true"     //是否启用SqlMapClient上的缓存机制。建议true  
  7.         enhancementEnabled="true"      //是否针对pojo启用字节码增强机制以提升getter/setter的调用性能,避免使用         
  8.   
  9.                 //reflect的性能开销,同时也为lazy loading带来了极大的性能提升。  
  10.              lazyLoadingEnabled="true"     //延迟加载  
  11.         errorTracingEnabled="true"     //是否启用错误日志  
  12.         maxRequests="32"          //最大请求并发数(statement并发数)  
  13.              maxSessions="10"         //最大的sqlmapclient数。介于>maxtransactions和<=maxrequests之间  
  14.         maxTransactions="5"         //最大并发事务数  
  15.         useStatementNamespaces="false" />  //是否使用Statement命名空间。这里的命名空间指的是映射文件中,sqlMap节点  
  16.                             的namespace属性,如在上例中针对t_user表的映射文件sqlMap节点:  
  17.                             <sqlMap namespace="User">这里,指定了此sqlMap节点下定义的操作均从  
  18.                             属于"User"命名空间。在useStatementNamespaces="true"的情况下,  
  19.   
  20. Statement调用需追加命名空间,如:  
  21.                             sqlMap.update("User.updateUser",user);否则直接通过Statement名称调用  
  22.   
  23. 即可,如:  
  24.                             sqlMap.update("updateUser",user);但请注意此时需要保证所有映射文件中  
  25.   
  26. ,Statement定义无重名。  
  27.      <transactionManager type="JDBC">   
  28.          <dataSource type="SIMPLE">   
  29.              <property name="JDBC.Driver" value="com.mysql.jdbc.Driver" />   
  30.              <property name="JDBC.ConnectionURL" value="jdbc:mysql://localhost:8080/sample" />   
  31.              <property name="JDBC.Username" value="root" />   
  32.              <property name="JDBC.Password" value="123456" />   
  33.              <property name="Pool.MaximumActiveConnections" value="10" />   
  34.              <property name="Pool.MaximumIdleConnections" value="5" />   
  35.              <property name="Pool.MaximumCheckoutTime" value="120000" />   
  36.              <property name="Pool.TimeToWait" value="500" />   
  37.              <property name="Pool.PingQuery" value="select 1 from ACCOUNT" />   
  38.              <property name="Pool.PingEnabled" value="false" />   
  39.              <property name="Pool.PingConnectionsOlderThan" value="1" />   
  40.              <property name="Pool.PingConnectionsNotUsedFor" value="1" />   
  41.           dataSource>   
  42.       transactionManager>   
  43.      <sqlMap resource="com/hengji/sql/User.xml" />   
  44.   sqlMapConfig>    

transactionManager节点定义了事务管理器,目前提供两种:

jdbc

jta

external外部事务管理,spring等

dataSource:

type(simple/dbcp/jndi)

xml 代码  

  1. <transactionManager type="JDBC" >  
  2.     <dataSource type="JNDI">  
  3.         <property name="DataSource" value="java:comp/env/jdbc/myDataSource"/>  
  4.     dataSource>  
  5. transactionManager>  

xml 代码  

  1. <typeAlias alias="user" type="com.ibatis.sample.User"/>  
  2. <cacheModel id="userCache" type="LRU">  
  3.     <flushInterval hours="24"/>            //设定缓存有效期,如果超过此设定值,则将此CacheModel的缓存清空。  
  4.     <flushOnExecute statement=" updateUser"/>    //指定执行特定Statement时,将缓存清空。  
  5.     <property name="size" value="1000" />        //本CacheModel中最大容纳的数据对象数量。  
  6. cacheModel>  

typeAlias定义了本映射文件中的别名,以避免过长变量值的反复书写,此例中通过typeAlias节点为类"com.ibatis.sample.User"定义了一个别名"user",
这样在本配置文件的其他部分,需要引用"com.ibatis.sample.User"类时,只需以其别名替代即可。

这里申明了一个名为"userCache"的cacheModel,之后可以在Statement申明中对其进行引用:

xml 代码  

  1. <select id="getUser"  
  2. parameterClass="java.lang.String"  
  3. resultClass="user"  
  4. cacheModel="userCache"  
  5. >  

-------------------------------------------

ibatis高级特性

1,一对多关联

xml 代码  

  1. <sqlMap namespace="User">  
  2. <typeAlias alias="user" type="com.ibatis.sample.User"/>  
  3. <typeAlias alias="address" type="com.ibatis.sample.Address"/>  
  4. <resultMap id="get-user-result" class="user">  
  5. <result property="id" column="id"/>  
  6. <result property="name" column="name"/>  
  7. <result property="sex" column="sex"/>  
  8. <result property="addresses" column="id"  
  9. select="User.getAddressByUserId"/>  
  10. </resultMap>  
  11. <select id="getUsers"  
  12. parameterClass="java.lang.String"  
  13. resultMap="get-user-result">  
  14. <![CDATA[ 
  15. select 
  16. id, 
  17. name, 
  18. sex 
  19. from t_user 
  20. where id = #id# 
  21. ]]>  
  22. </select>  
  23. <select id="getAddressByUserId"  
  24. parameterClass="int"  
  25. resultClass="address">  
  26. <![CDATA[ 
  27. select 
  28. address, 
  29. zipcode 
  30. from t_address 
  31. where user_id = #userid# 
  32. ]]>  
  33. </select>  
  34. </sqlMap>  

这里通过在resultMap 中定义嵌套查询getAddressByUserId,我们实现了关联数据的读取。实际上,这种方式类似于前面所说的通过两条单独的Statement 进行关联数据的读取,只是将关联关系在配置中加以描述,由ibatis自动完成关联数据的读取。

如果t_user 表中记录较少,不会有明显的影响,假设t_user 表中有十万条记录,那么这样的操作将需要100000+1 条Select语句反复执行才能获得结果,无疑,随着记录的增长,这样的开销将无法承受。

延迟加载

Settings 节点有两个与延迟加载相关的属性lazyLoadingEnabled 和enhancementEnabled,其中lazyLoadingEnabled设定了系统是否使用延迟加载机制,enhancementEnabled设定是否启用字节码强化机制(通过字节码强化机制可以为Lazy Loading带来性能方面的改进。

xml 代码  

  1. <dynamic prepend="WHERE">  
  2.     <isNotEmpty prepend="AND" property="name">  
  3.         (name like #name#)  
  4.     </isNotEmpty>  
  5.     <isNotEmpty prepend="AND" property="address">  
  6.         (address like #address#)  
  7.     </isNotEmpty>  
  8. </dynamic>  

通过dynamic 节点,我们定义了一个动态的WHERE 子句。此WHERE 子句中将可能包含两个针对name 和address 字段的判断条件。而这两个字段是否加入检索取决于用户所提供的查询条件(字段是否为空[isNotEmpty])。

事务处理:

java 代码  

  1. sqlMap = xmlBuilder.buildSqlMap(reader);  
  2. sqlMap.startTransaction();  
  3.     User user = new User();  
  4.     user.setId(new Integer(1));  
  5.     user.setName("Erica");  
  6.     user.setSex(new Integer(0));  
  7.     sqlMap.update("User.updateUser", user);  
  8. sqlMap.commitTransaction();  
  9.   
  10. sqlMap.endTransaction();  

cache应用:

cache几个重要属性

1.readonly

readOnly值的是缓存中的数据对象是否只读。这里的只读并不是意味着数据对象一旦放入缓存中就无法再对数据进行修改。而是当数据对象发生变化的时候,如数据对象的某个属性发生了变化,则此数据对象就将被从缓存中废除,下次需要重新从数据库读取数据,构造新的数据对象。而readOnly="false"则意味着缓存中的数据对象可更新,如user 对象的name属性发生改变。

只读Cache能提供更高的读取性能,但一旦数据发生改变,则效率降低。系统设计时需根据系统的实际情况(数据发生更新的概率有多大)来决定Cache的读写策略。

2.serialize

如果需要全局的数据缓存,CacheModel的serialize属性必须被设为true。否则数据缓存只对当前Session(可简单理解为当前线程)有效,局部缓存对系统的整体性能提升有限。

在serialize="true"的情况下,如果有多个Session同时从Cache 中读取某个数据对象,Cache 将为每个Session返回一个对象的复本,也就是说,每个Session 将得到包含相同信息的不同对象实例。因而Session 可以对其从Cache 获得的数据进行存取而无需担心多线程并发情况下的同步冲突。

3.type

在生产部署时,建议采用OSCache,OSCache 是得到了广泛使用的开源Cache 实现(Hibernate 中也提供了对OSCache 的支持),它基于更加可靠高效的设计,更重要的是,最新版本的OSCache 已经支持Cache 集群。如果系统需要部署在集群中,或者需要部署在多机负载均衡模式的环境中以获得性能上的优势,那么OSCache在这里则是不二之选。

xml 代码  

  1. <cacheModel id="userCache" type="OSCACHE">  
  2. <flushInterval hours="24"/>  
  3. <flushOnExecute statement="updateUser"/>  
  4. <property name="size" value="1000" />  
  5. </cacheModel>  

火龙果软件/UML软件工程组织致力于提高您的软件工程实践能力,我们不断地吸取业界的宝贵经验,向您提供经过数百家企业验证的有效的工程技术实践经验,同时关注最新的理论进展,帮助您“领跑您所在行业的软件世界”。
资源网站: UML软件工程组织