Jameslyy 发表于 2013-1-13 18:56:16

iBATIS tips

1、iBATIS的配置文件
2、对象映射文件
3、编写应用程序
4、自动生成主键
5、DB2保存数据空值问题
6、传入参数
7、Result Map
8、复杂类型属性
9、缓存Mapped Statement结果集
10、动态Mapped Statement
11、事务处理
12、批处理
13、分页查询
14、Ibator
 
      iBATIS 在Java和.NET两种环境下都可以使用,它使得使用数据库变得很容易,iBATIS 通过XML描述文件确定对象和存储过程/SQL语句之间的对应关系。简单是iBATIS DATA Mapper 作为对象关系映射工具最大的优点。
      要使用iBATISData Mapper,依赖于你的对象、XML、SQL,不需要学习很多你不知道的东西,iBATISData Mapper 就可以很方便地获得SQL和存储过程全部强大的能力。
 
      Hibernate、Apache OJB这类ORM框架拥有自己的查询语言,和他们不同的是,iBATIS直接使用SQL,这具有局限性,也就是不能跨数据库使用,需要针对每一种数据库调整SQL语句,但也拥有很大的优点,直接使用SQL使得框架实现变得很简单,映射效率上的可能空间更大一些,可以直接使用SQL实现更高的数据库访问效率,直接使用SQL的特性使得iBATIS在某一些应用环境下更为适合开发的要求。
 
1、iBATIS的配置文件:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE sqlMapConfigPUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN""http://www.ibatis.com/dtd/sql-map-config-2.dtd"><!-- Always ensure to use the correct XML header as above! --><sqlMapConfig><!-- The properties (name=value) in the file specified here can be used placeholders               in this config file (e.g. “${driver}”.                The file is relative to the classpath and is completely optional. --><properties resource="com/ibatis/SqlMapConfig.properties" /><!-- These settings control SqlMap configuration details, primarily to do with               transaction management. They are all optional (see the Developer Guide               for more). --><settingscacheModelsEnabled="true"enhancementEnabled="true"lazyLoadingEnabled="true"maxRequests="32"maxSessions="10"maxTransactions="5"useStatementNamespaces="false"/><!-- Type aliases allow you to use a shorter name for long fully               qualified class names. --><typeAlias alias="order" type="testdomain.Order"/><!-- Configure a datasource to use with this SQL Map using SimpleDataSource.Notice the use of the properties from the above resource --><transactionManager type="JDBC" ><dataSource type="SIMPLE"><property name="JDBC.Driver" value="${driver}"/><property name="JDBC.ConnectionURL" value="${url}"/><property name="JDBC.Username" value="${username}"/><property name="JDBC.Password" value="${password}"/><!-- SIMPLE --><property name="JDBC.DefaultAutoCommit" value="true" /><property name="Pool.MaximumActiveConnections" value="10"/><property name="Pool.MaximumIdleConnections" value="5"/><property name="Pool.MaximumCheckoutTime" value="120000"/><property name="Pool.TimeToWait" value="500"/><property name="Pool.PingQuery" value="select 1 from ACCOUNT"/><property name="Pool.PingEnabled" value="false"/><property name="Pool.PingConnectionsOlderThan" value="1"/><property name="Pool.PingConnectionsNotUsedFor" value="1"/></dataSource></transactionManager><!-- Identify all SQL Map XML files to be loaded by this SQL map. Notice the pathsare relative to the classpath. For now, we only have one --><sqlMap resource="com/ibatis/sample/User.xml" /><!-- <sqlMap url="file:///c:/config/User.xml " /> --></sqlMapConfig> 事务管理器别名
    JDBC     com.ibatis.sqlmap.engine.transaction.jdbc.JdbcTransactionConfig
    JTA      com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig
    EXTERNAL com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig

Data Source Factory别名
    SIMPLE   com.ibatis.sqlmap.engine.datasource.SimpleDataSourceFactory
    DBCP     com.ibatis.sqlmap.engine.datasource.DbcpDataSourceFactory
    JNDI     com.ibatis.sqlmap.engine.datasource.JndiDataSourceFactory
 
DBCP的配置
    <property name="Pool.MaximumActiveConnections" value="10"/>    <property name="Pool.MaximumIdleConnections" value="5"/>    <property name="Pool.MaximumWait" value="60000"/>    <!--         Use of the validation query can be problematic.If you have difficulty,         try without it.   -->    <property name="Pool.ValidationQuery" value="select 1 from ACCOUNT"/>    <property name="Pool.LogAbandoned" value="false"/>    <property name="Pool.RemoveAbandoned" value="false"/>    <property name="Pool.RemoveAbandonedTimeout" value="50000"/> 
JNDI JTA
<transactionManager type="JDBC" >    <dataSource type="JNDI">          <property name="DataSource" value="java:comp/env/jdbc/jpetstore"/>    </dataSource></transactionManager><transactionManager type="JTA" >    <property name="UserTransaction" value="java:/ctx/con/UserTransaction"/>    <dataSource type="JNDI">          <property name="DataSource" value="java:comp/env/jdbc/jpetstore"/>    </dataSource></transactionManager> 
2、对象映射文件
<sqlMap id=”Product”>    <cacheModel id=”productCache” type=”LRU”>      <flushInterval hours=”24”/>      <property name=”size” value=”1000” />    </cacheModel>    <typeAlias alias=”product” type=”com.ibatis.example.Product” />    <parameterMap id=”productParam” class=”product”>      <parameter property=”id”/>    </parameterMap>    <resultMap id=”productResult” class=”product”>      <result property=”id” column=”PRD_ID”/>      <result property=”description” column=”PRD_DESCRIPTION”/>    </resultMap>    <select id=”getProduct” parameterMap=”productParam”      resultMap=”productResult” cacheModel=”product-cache”>            select * from PRODUCT where PRD_ID = ?    </select></sqlMap> 
也可以简化来写:
<sqlMap id=”Product”><select id=”getProduct” parameterClass=” com.ibatis.example.Product”         resultClass=”com.ibatis.example.Product”>selectPRD_ID as id,PRD_DESCRIPTION as descriptionfrom PRODUCTwhere PRD_ID = #id#</select></sqlMap> 为了在SQL语句中使用特殊符号可以把SQL放在XML中的CDATA里面:
<statement id="getPersonsByAge" parameterClass=”int”   resultClass="examples.domain.Person"><!]></statement> 
3、编写应用程序
import com.ibatis.common.resources.Resources;import com.ibatis.sqlmap.client.SqlMapClient;import com.ibatis.sqlmap.client.SqlMapClientBuilder;try {    String resource = "com/simple/SqlMapConfig.xml";    Reader reader = Resources.getResourceAsReader(resource);    SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);} catch (Exception e) {    e.printStackTrace();    throw new RuntimeException(    "Error initializing TourPlanIBatisConfig class. Cause: " + e);} 
SqlMapClient 接口拥有各种操作数据库的方法,例如:
    sqlMap.queryForObject (“getPerson”, personPk);
    sqlMap.update(“updatePerson”, person);
 
4、自动生成主键
<!—Oracle SEQUENCE Example --><insert id="insertProduct-ORACLE" parameterClass="com.domain.Product"><selectKey resultClass="int" keyProperty="id" >SELECT STOCKIDSEQUENCE.NEXTVAL AS ID FROM DUAL</selectKey>insert into PRODUCT (PRD_ID,PRD_DESCRIPTION)values (#id#,#description#)</insert><!— Microsoft SQL Server IDENTITY Column Example --><insert id="insertProduct-MS-SQL" parameterClass="com.domain.Product">insert into PRODUCT (PRD_DESCRIPTION)values (#description#)<selectKey resultClass="int" keyProperty="id" >SELECT @@IDENTITY AS ID</selectKey></insert> 大多数数据库的写法如下:
<selectKey>CloudscapeVALUES IDENTITY_VAL_LOCAL()DB2         VALUES IDENTITY_VAL_LOCAL()Derby       VALUES IDENTITY_VAL_LOCAL()HSQLDB      CALL IDENTITY()MySql       SELECT LAST_INSERT_ID()SqlServer   SELECT SCOPE_IDENTITY()SYBASE      SELECT @@IDENTITYORACLE      SELECT CUSTOM_SQL.NEXTVAL AS ID FROM DUAL  
5、DB2保存数据空值问题
    iBATIS使用prepareStatement,在没有显示mapping定义数据类型的情况下,首先使用参数值的java类型决定传输给prepareStatement的参数类型,如果参数是值是null,则使用Type.OTHER 。在DB2的driver下,Type.OTHER类型不能正确执行。要解决这个问题,就要在mapping中显示声明参数(列)的类型:
        1、对于bean参数进行可以如下声明:
            <insert  id="userInsert" parameterClass="com.sample.User">
                     insert into USER(USERID) VALUES (#userId:VARCHAR#)
            </insert>

        2、对于map参数,可以使用parameterMap定义每个参数的类型
            <parameterMap class="com.sample.User" id="userMap">
                   <parameter  property="userId" typeName="VARCHAR"  />
            </parameterMap>
 
6、传入参数
 
    parameterMap
<parameterMap id=”insert-product-param”   class=”com.domain.Product”>    <parameter property=”id” jdbcType=”NUMERIC” javaType=”int” nullValue=”-9999999”/>    <parameter property=”description” jdbcType=”VARCHAR” nullValue=”NO_ENTRY”/>    </parameterMap><statement id=”insertProduct” parameterMap=”insert-product-param”>    insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (?,?);</statement>     Inline Parameter Map
<statement id=”insertProduct”    parameterClass=”com.domain.Product”>    insert into PRODUCT (PRD_ID, PRD_DESCRIPTION)values (#id#, #description#);</statement>在内嵌参数中指定数据类型可以用下面的语法:<statement id=”insertProduct”   parameterClass=”com.domain.Product”>    insert into PRODUCT (PRD_ID, PRD_DESCRIPTION)    values (#id:NUMERIC#, #description:VARCHAR#);</statement>在内嵌参数中指定数据类型和NULL的替代值可以用这样的语法:<statement id=”insertProduct”   parameterClass=”com.domain.Product”>    insert into PRODUCT (PRD_ID, PRD_DESCRIPTION)    values (#id:NUMERIC:-999999#, #description:VARCHAR:NO_ENTRY#);</statement>     基本类型输入参数
<statement id=”insertProduct” parameter=”java.lang.Integer”>    select * from PRODUCT where PRD_ID = #value#</statement>     Map类型输入参数
<statement id=”insertProduct” parameterClass=”java.util.Map”>    select * from PRODUCT    where PRD_CAT_ID = #catId# and PRD_CODE = #code#</statement> 
7、Result Map
<resultMap id=”get-product-result” class=”com.ibatis.example.Product”>    <result property=”id” column=”PRD_ID”/>    <result property=”description” column=”PRD_DESCRIPTION”/>    <result property=”subCode” column=”PRD_SUB_CODE” nullValue=”-999”/></resultMap> 
    隐式的Result Map
<statement id=”getProduct” resultClass=”com.ibatis.example.Product”>    select    PRD_ID as id,    PRD_DESCRIPTION as description    from PRODUCT    where PRD_ID = #value#</statement> 
    基本类型的Result(即String,Integer,Boolean)
<resultMap id=”get-product-result” class=”java.lang.String”>    <result property=”value” column=”PRD_DESCRIPTION”/></resultMap><statement id=”getProductCount” resultClass=”java.lang.Integer”>    select count(1) as value    from PRODUCT</statement> 
    Map类型的Result
<resultMap id=”get-product-result” class=”java.util.HashMap”>    <result property=”id” column=”PRD_ID”/>    <result property=”code” column=”PRD_CODE”/>    <result property=”description” column=”PRD_DESCRIPTION”/>    <result property=”suggestedPrice” column=”PRD_SUGGESTED_PRICE”/></resultMap> 8、复杂类型属性
<resultMap id=”get-product-result” class=”com.ibatis.example.Product”>    <result property=”id” column=”PRD_ID”/>    <result property=”description” column=”PRD_DESCRIPTION”/>    <result property=”category” column=”PRD_CAT_ID” select=”getCategory”/></resultMap><resultMap id=”get-category-result” class=”com.ibatis.example.Category”>    <result property=”id” column=”CAT_ID”/>    <result property=”description” column=”CAT_DESCRIPTION”/></resultMap><statement id=”getProduct” parameterClass=”int” resultMap=”get-product-result”>    select * from PRODUCT where PRD_ID = #value#</statement><statement id=”getCategory” parameterClass=”int” resultMap=”get-category-result”>    select * from CATEGORY where CAT_ID = #value#</statement>  避免N+1 Select(1:1)
<resultMap id=”get-product-result” class=”com.ibatis.example.Product”>    <result property=”id” column=”PRD_ID”/>    <result property=”description” column=”PRD_DESCRIPTION”/>    <result property=”category.id” column=”CAT_ID” />    <result property=”category.description” column=”CAT_DESCRIPTION” /></resultMap><statement id=”getProduct” parameterClass=”int” resultMap=”get-product-result”>    select *    from PRODUCT, CATEGORY    where PRD_CAT_ID=CAT_ID    and PRD_ID = #value#</statement> 
 复杂类型集合的属性
<resultMap id=”get-category-result” class=”com.ibatis.example.Category”>    <result property=”id” column=”CAT_ID”/>    <result property=”description” column=”CAT_DESCRIPTION”/>    <result property=”productList” column=”CAT_ID” select=” getProductsByCatId”/></resultMap><resultMap id=”get-product-result” class=”com.ibatis.example.Product”>    <result property=”id” column=”PRD_ID”/>    <result property=”description” column=”PRD_DESCRIPTION”/></resultMap><statement id=”getCategory” parameterClass=”int” resultMap=”get-category-result”>    select * from CATEGORY where CAT_ID = #value#</statement><statement id=”getProductsByCatId” parameterClass=”int” resultMap=”get-product-result”>    select * from PRODUCT where PRD_CAT_ID = #value#</statement> 
 组合键值或多个复杂参数属性
<resultMap id=”get-order-result” class=”com.ibatis.example.Order”>    <result property=”id” column=”ORD_ID”/>    <result property=”customerId” column=”ORD_CST_ID”/>    …    <result property=”payments” column=”{itemId=ORD_ID, custId=ORD_CST_ID}”select=” getOrderPayments”/></resultMap><statement id=”getOrderPayments” resultMap=”get-payment-result”>    select * from PAYMENT    where PAY_ORD_ID = #itemId#            and PAY_CST_ID = #custId#</statement> 
9、缓存Mapped Statement结果集
    通过在查询statement中指定cacheModel属性,可以缓存Mapped Statement中得到的查询结果。
Cache model是在SQL Map XML文件中定义的可配置缓存模式,可以使用cacheModel元素来配置。
<cacheModel id="product-cache" type ="LRU" readOnly=”true” serialize=”false”>    <flushInterval hours="24"/>    <flushOnExecute statement="insertProduct"/>    <flushOnExecute statement="updateProduct"/>    <flushOnExecute statement="deleteProduct"/>    <property name=”cache-size” value=”1000” /></cacheModel>LRU: 近期最少使用
 
<statement id=”getProductList” cacheModel=”product-cache”>    select * from PRODUCT where PRD_CAT_ID = #value#</statement> 
缓存类型:
    “MEMORY” (com.ibatis.db.sqlmap.cache.memory.MemoryCacheController)
          只对“reference-type”属性产生作用,value:STRONG,SOFT和WEAK,默认WEAK。
          <property name=”reference-type” value=”WEAK” />
    “LRU” (com.ibatis.db.sqlmap.cache.lru.LruCacheController)
          “近期最少使用”原则。只对“cache-size”属性产生作用。
          <property name=”cache-size” value=”1000” />
    “OSCACHE” (com.ibatis.db.sqlmap.cache.oscache.OSCacheController)
 
10、动态Mapped Statement
<statement id="dynamicGetAccountList" resultMap="account-result" >    select * from ACCOUNT    <dynamic prepend="WHERE">      <isNotNull prepend="AND" property="firstName">            (ACC_FIRST_NAME = #firstName#            <isNotNull prepend="OR" property="lastName">               ACC_LAST_NAME = #lastName#            </isNotNull>            )      </isNotNull>      <isNotNull prepend="AND" property="emailAddress">            ACC_EMAIL like #emailAddress#      </isNotNull>      <isGreaterThan prepend="AND" property="id" compareValue="0">            ACC_ID = #id#      </isGreaterThan>    </dynamic>    order by ACC_LAST_NAME</statement> 
11、事务处理
String resource = “com/ibatis/example/sqlMap-config.xml”;Reader reader = Resources.getResourceAsReader (resource);SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMap(reader); 
public void startTransaction () throws SQLExceptionpublic void commitTransaction () throws SQLExceptionpublic void endTransaction () throws SQLException  
private Reader reader = new Resources.getResourceAsReader(      "com/ibatis/example/sqlMapconfig.xml");private SqlMapClient sqlMap = XmlSqlMapBuilder.buildSqlMap(reader);public updateItemDescription (String itemId, String newDescription) throws SQLException {    try {      sqlMap.startTransaction ();      Item item = (Item) sqlMap.queryForObject ("getItem", itemId);      item.setDescription (newDescription);      sqlMap.update ("updateItem", item);      sqlMap.commitTransaction ();    } finally {      sqlMap.endTransaction ();    }}      事务不能嵌套。在调用commit()或rollback()之前,从同一线程多次调用.startTransaction,将引起抛出例外。换句话说,对于每个SqlMap实例,每个线程最多只能打开一个事务。
      SqlMapClient事务处理使用Java的ThreadLocal保存事务对象。这意味着在处理事务时,每个调用startTransaction()的线程,将得到一个唯一的Connection对象。将一个Connection对象返回数据源(或关闭连接)唯一的方法是调用commitTransaction()或rollbackTransaction()方法。否则,会用光连接池中的连接并导致死锁。
 
12、批处理
sqlMap.startBatch();//…execute statements in betweensqlMap.executeBatch(); 13、分页查询
PaginatedList list = sqlMap.queryForPaginatedList (“getProductList”, null, 10);list.nextPage();list.previousPage(); 14、Ibator:iBatis 的自动生成工具
    http://ibatis.apache.org/ibator.html
    建议:如果使用 Ibator,就不要试图去修改其生成的代码,能够使用就可以了,不然会带来很大麻烦。如果需要自己编写定制的、高性能的SQL,就不要使用Ibator了。
 
 
 
页: [1]
查看完整版本: iBATIS tips