iBatis

来源:互联网 发布:淘宝店铺职位 编辑:程序博客网 时间:2024/06/02 03:02

转自:http://www.24xuexi.com/w/2011-10-09/97936.html


ibatis的作用:

SQL Map能大大减少访问关系数据库的代码。SQL Map使用简单的XML配置文件将Java Bean映射成SQL语句,对比其他的数据库持久层和ORM框架,SQL Map最大的优点在于它简单易学。要使用SQL Map,只要熟悉JavaBean,XML和SQL就能充分发挥SQL语句的能力。也就是说ibatis是用来简化我们对数据库操作的,就是把SQL跟bean挂钩

 

具体的细节:

将一个对象作为参数,用对象参数来设定SQL语句的参数。1、执行mapped statement。用对象为PreparedStatement设置参数,执行PreparedStatement从ResultSet创建结果对象。 2、执行SQL的更新数据语句时,返回受影响的数据行数。执行查询语句时,将返回一个结果对象或对象的集合。和参数对象一样,结果对象可以是Java Bean,Map实现和基本数据类型的包装类。
sqlMapConfig配置文件的作用就不多说了,有时候我们学一个东西的时候上来就想让他开始运行,而不是抓耳挠腮地去揣摩这些很零散的东东是干什么用的。不过在需要的时候就会发现,这些东西还是不得不知道的,最起码我们得知道他们常用的属性吧。

 

<?xml version="1.0"encoding="UTF-8" ?><!DOCTYPE sqlMapConfigPUBLIC"-//iBATIS.com//DTD SQL Map Config2.0//EN""http://www.ibatis.com/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

<properties resource="examples/sqlmap/maps/SqlMapConfigExample.properties"/>

<settingscacheModelsEnabled="true"enhancementEnabled="true"lazyLoadingEnabled="true"maxRequests="32"maxSessions="10"maxTransactions="5"useStatementNamespaces="false"/>

<typeAlias alias="order"type="testdomain.Order"/><transactionManager type="JDBC">

<dataSource type="SIMPLE">

<property name="JDBC.Driver"value="${driver}"/>

<propertyname="JDBC.ConnectionURL" value="${url}"/>

<property name="JDBC.Username"value="${username}"/>

<property name="JDBC.Password"value="${password}"/>

<property name="JDBC.DefaultAutoCommit"value="true" />

<propertyname="Pool.MaximumActiveConnections" value="10"/>

<propertyname="Pool.MaximumIdleConnections" value="5"/>

<propertyname="Pool.MaximumCheckoutTime" value="120000"/>

<propertyname="Pool.TimeToWait" value="500"/>

<propertyname="Pool.PingQuery" value="select 1 from ACCOUNT"/>

<propertyname="Pool.PingEnabled" value="false"/>

<propertyname="Pool.PingConnectionsOlderThan" value="1"/>

<propertyname="Pool.PingConnectionsNotUsedFor" value="1"/>

</dataSource>

</transactionManager>

<sqlMapresource="examples/sqlmap/maps/Person.xml" />

</sqlMapConfig>

 

1、<properties>元素用来配置java的标准属性文件。如果属性文件中包括 driver=org.hsqldb.jdbcDriver,那可以使用占位符${driver}来代表值org.hsqldb.jdbcDriver。 属性文件中的值可以用<propertyname="JDBC.Driver" value="${driver}"/>来设置。可以在不同的环境中用这个来配置不同的信息。而不是直接该XML文件中的值。补充 下,properties属性是可以用url来设置的。
2、<setting>元素用于配置和优化 SqlMapClient实例的各选项。它所包含的属性如下:maxRequests:同时执行SQL语句的最大线程数。maxSessions:同一时 间内活动的最大session数。maxTransactions:同时进入SqlMapClient.startTransaction()的最大线程数。cacheModelsEnabled:全局性地启用或禁用SqlMapClient的所有缓存model。调试程序时使用。 lazyLoadingEnabled:全局性地启用或禁用SqlMapClient的所有延迟加载。调试程序时使用。 enhancementEnabled:全局性地启用或禁用运行时字节码增强,以优化访问Java Bean属性的性能,同时优化延迟加载的性能。useStatementNamespaces:如果启用本属性,必须使用全限定名来引用mapped statement。
3、<typeAlias>元素让您为一个通常较长的、全限定类名指定一个较短的别名。例:<typeAliasalias="shortname" type="com.long.class.path.Class"/>
4、<transationManager>元素让您为SQL Map配置事务管理服务。属性type指定所使用的事务管理器类型。这个属性值可以是一个类名,也可以是一个别名。包含在框架的三个事务管理器分别是:JDBC,JTA和EXTERNAL。
5、<datasource><transactionManager>的一部分,为SQL Map数据源设置了一系列参数。
DataSource Factory的三个实现及其例子:A、SimpleDataSourceFactory为 DataSource提供了一个基本的实现,适用于在没有J2EE容器提供DataSource的情况。它基于iBatis的 SimpleDataSource连接池实现。

<transactionManagertype="JDBC"><dataSource type="SIMPLE">

<propertyname="JDBC.Driver" value="org.postgresql.Driver"/>

<propertyname="JDBC.ConnectionURL"value="jdbc:postgresql://server:5432/dbname"/>

<propertyname="JDBC.Username" value="user"/><propertyname="JDBC.Password" value="password"/>

<propertyname="Pool.MaximumActiveConnections"value="10"/>

<propertyname="Pool.MaximumIdleConnections"value="5"/>

<property name="Pool.MaximumCheckoutTime"value="120000"/>

<property name="Pool.TimeToWait"value="10000"/>

<property name="Pool.PingQuery"value="select * from dual"/><propertyname="Pool.PingEnabled" value="false"/><propertyname="Pool.PingConnectionsOlderThan"value="0"/>

<propertyname="Pool.PingConnectionsNotUsedFor"value="0"/>

</dataSource></transactionManager>
B、DbcpDataSourceFactory实 现使用Jakarta DBCP(Database Connection Pool)的DataSource API提供连接池服务。适用于应用/Web容器不提供DataSource服务的情况,或执行一个单独的应 用。

<transactionManager type="JDBC">

<dataSourcetype="DBCP">

<property name="JDBC.Driver"value="${driver}"/>

<propertyname="JDBC.ConnectionURL" value="${url}"/>

<property name="JDBC.Username"value="${username}"/>

<property name="JDBC.Password"value="${password}"/>

<propertyname="Pool.MaximumActiveConnections"value="10"/>

<propertyname="Pool.MaximumIdleConnections"value="5"/>

<property name="Pool.MaximumWait"value="60000"/>

<property name="Pool.ValidationQuery"value="select * from ACCOUNT"/>

<propertyname="Pool.LogAbandoned" value="false"/>

<propertyname="Pool.RemoveAbandoned" value="false"/>

<propertyname="Pool.RemoveAbandonedTimeout" value="50000"/>

</datasource></transactionManager>
C、JndiDataSourceFactory在 应用容器内部从JNDI Context中查找DataSource实现。当使用应用服务器,并且服务器提供了容器管理的连接池和相关DataSource实现的情况下,可以使用 JndiDataSourceFactory。使用JDBC DataSource的标准方法是通过JNDI来查找。

<transactionManagertype="JDBC" >

<dataSource type="JNDI">

<propertyname="DataSource" value="java:comp/env/jdbc/jpetstore"/>

</dataSource>

</transactionManager>AND<transactionManagertype="JTA" >

<property name="UserTransaction"value="java:/ctx/con/UserTransaction"/>

<dataSource type="JNDI">

<propertyname="DataSource" value="java:comp/env/jdbc/jpetstore"/>

</dataSource>

</transactionManager>
6、<sqlMap>元 素用于包括SQL Map映射文件和其他的SQL Map配置文件。每个SqlMapClient对象使用的所有SQL Map映射文件都要在此声明。映射文件作为stream resource从类路径或URL读入。您必须在这里指定所有的SQLMap文件。<sqlMapresource="com/ibatis/examples/sql/Customer.xml" /><sqlMapurl="file:///c:/config/Customer.xml " />这个到了真正动手的时候了,不过会发现依然继续要管理细节的东西,细节决定成败啊。。。先看个例子。。

<sqlMap id=”Product”>

<cacheModel id=”productCache”type=”LRU”>

<flushInterval hours=”24”/><property name=”size” value=”1000” />

</cacheModel>

<typeAliasalias=”product” type=”com.ibatis.example.Product” />

<parameterMap id=”productParam”class=”product”>

<parameterproperty=”id”/></parameterMap>

<resultMap id=”productResult”class=”product”>

<result property=”id” column=”PRD_ID”/>

<resultproperty=”description” column=”PRD_DESCRIPTION”/>

</resultMap>

<selectid=”getProduct” parameterMap=”productParam” resultMap=”productResult”cacheModel=”product-cache”>

select * from PRODUCT where PRD_ID =?

</select>

</sqlMap>

下面来慢慢解释其中的东东。。。Map Statement结 构:<statementid=”statementName”[parameterClass=”some.class.Name”][resultClass=”some.class.Name”][parameterMap=”nameOfParameterMap”][resultMap=”nameOfResultMap”][cacheModel=”nameOfCache”]>select* from PRODUCT where PRD_ID = [?|#propertyName#]order by[$simpleDynamic$]</statement><statement>元素是个通用声明,可以用于 任何类型的SQL语句。因为SQL语句是嵌在XML文档中的,因此有些特殊的字符不能直接使用,例如大于号和小于号(<>)。解决的办法很简 单,只需将包含特殊字符的SQL语句放在XML的CDATA区里面就可以了。如:<![CDATA[SELECT *FROM PERSONWHERE AGE > #value#]]>
自动生成主键:我们在数据库插入一条数据的时候,经常是需 要返回插入这条数据的主键。可以使用<selectKey>节点来获取<insert>语句所产生的主 键。?<insertid="insertProduct-ORACLE"parameterClass="com.domain.Product">

<selectKeyresultClass="int" keyProperty="id" >

SELECTSTOCKIDSEQUENCE.NEXTVAL AS ID FROM DUAL

</selectKey>

insert into PRODUCT (PRD_ID,PRD_DESCRIPTION)values(#id#,#description#)

</insert>
<insert id="insertProduct-MS-SQL"parameterClass="com.domain.Product">

insert into PRODUCT(PRD_DESCRIPTION)values (#description#)

<selectKeyresultClass="int" keyProperty="id" >SELECT @@IDENTITY ASID

</selectKey>

</insert>
存储过程:SQL Map通过<procedure>元 素支持存储过程如:<parameterMapid="swapParameters" class="map" ><parameterproperty="email1" jdbcType="VARCHAR"javaType="java.lang.String" mode="INOUT"/><parameterproperty="email2" jdbcType="VARCHAR"javaType="java.lang.String" mode="INOUT"/></parameterMap>
<procedure id="swapEmailAddresses"parameterMap="swapParameters" >{call swap_email_address (?,?)}</procedure>
parameterClass属性是可选的,但强烈建议使用。它的目的是限制输入参数的类型为指定的Java类,并优化框架的性能。如果您使用parameterMap,则没有必要使用parameterClass属性。
parameterMap属性的值等于一个预先定义的<parameterMap>元素的名称。
resultClass属 性可以让您指定一个Java类,根据ResultSetMetaData将其自动映射到JDBC的ResultSet。只要是Java Bean的属性名称和ResultSet的列名匹配,属性自动赋值给列值。这使得查询mappedstatement变得很短。如:<statementid="getPerson" parameterClass=”int”resultClass="examples.domain.Person">SELECT PER_ID asid,PER_FIRST_NAME as firstName,PER_LAST_NAME as lastName,PER_BIRTH_DATE asbirthDate,PER_WEIGHT_KG as weightInKilograms,PER_HEIGHT_M as heightInMetersFROMPERSONWHERE PER_ID = #value#</statement>
resultMap可 以控制数据如何从结果集中取出,以及哪一个属性匹配哪一个字段。不象使用resultClass的自动映射方法,resultMap属性可以允许指定字段 的数据类型,NULL的替代值复杂类型映射(包括其他Java Bean,集合类型和基本类型包装类)。如:

<resultMapid=”get-product-result” class=”com.ibatis.example.Product”>

<resultproperty=”id” column=”PRD_ID”/>

<result property=”description”column=”PRD_DESCRIPTION”/>

</resultMap><statement id=”getProduct”resultMap=”get-product-result”>select * from PRODUCT</statement>
cacheModel的属性值等于指定的cacheModel元素的name 属性值。属性cacheModel定义查询mapped statement的缓存。每一个查询mapped statement可以使用不同或相同的cacheModel。

<cacheModelid="product-cache" imlementation="LRU">

<flushIntervalhours="24"/>

<flushOnExecutestatement="insertProduct"/>

<flushOnExecutestatement="updateProduct"/>

<flushOnExecutestatement="deleteProduct"/>

<property name=”size” value=”1000” />

</cacheModel>

<statementid=”getProductList” parameterClass=”int”cacheModel=”product-cache”>select* from PRODUCT where PRD_CAT_ID = #value#</statement>
xmlResultName属性: 当直接把查询结果映射成XML document时,属性xmlResultName的值等于XML document根元素的名称。例如:

<select id="getPerson" parameterClass=”int”resultClass="xml" xmlResultName=”person”>SELECT PER_ID asid,PER_FIRST_NAME as firstName,PER_LAST_NAME as lastName,PER_BIRTH_DATE asbirthDate,PER_WEIGHT_KG as weightInKilograms,PER_HEIGHT_M as heightInMetersFROMPERSONWHERE PER_ID = #value#</select>

上面的查询结果将产生一个XML document,结构如 下:

<person><id>1</id><firstName>Clinton</firstName><lastName>Begin</lastName><birthDate>1900-01-01</birthDate>

<weightInKilograms>89</weightInKilograms>

<heightInMeters>1.77</heightInMeters>

</person>
parameterMap负 责将Java Bean的属性映射成statement的参数。如:

<parameterMapid=”parameterMapName” [class=”com.domain.Product”]>

<parameter property=”propertyName” [jdbcType=”VARCHAR”] [javaType=”string”][nullValue=”NUMERIC”][null=”-9999999”]/>

<parameter…… />

<parameter …… />

</parameterMap>
<parameter>元素的属性:property属性是传给statement的参数对象的Java Bean属性名称。jdbcType属性用于显式地指定给本属性(property)赋值的数据库字段的数据类型。javaType属性用于显式地指定被赋值参数Java属性的类名。nullValue属性可以是对于property类型来说任意的合法值,用于指定NULL的替换值。
基本输入类型:假 如没必要写一个Java Bean作为参数,可以直接使用基本类型的包装类(即String,Integer,Date等)作为参数。如:

<statement id=”insertProduct”parameter=”java.lang.Integer”>select * from PRODUCT where PRD_ID =#value#</statement>
Map类型输入参数:假如没 必要写一个Java Bean作为参数,而要传入的参数又不只一个时,可以使用Map类(如HashMap,TreeMap等)作为参数对象。如:<statementid=”insertProduct” parameterClass=”java.util.Map”>select * fromPRODUCT?where PRD_CAT_ID = #catId#?and PRD_CODE = #code#</statement>在这个中要注意的是得有相同类型的名称的参数,并且相应的类型也要相同。
Result Map:在执行查询Mapped Statement时,resultMap负责将结果集的列值映射成Java Bean的属性值。 如:

<resultMap id=”resultMapName” class=”some.domain.Class”[extends=”parent-resultMap”]>(extends的作用感觉有点像类继承)

<result property=”propertyName” column=”COLUMN_NAME”(property返回对象的bean属性的名称,column是ResultSet中字段的名称) [columnIndex=”1”]?[javaType=”int”] (指定java bean属性的类型)[jdbcType=”NUMERIC”](指定ResultSet中用于赋值java bean属性字段的数据库数据类型)[nullValue=”-999999”](指定数据库中null值的代替值)?[select=”someOtherStatement”](用于描述对象和对象之间的关系,并自动地装入复杂类型属性的数据)/>< result ……/>

</resultMap>
隐式的Result Map:通过设定mapped statement的resultClass属性来隐式地指定result map。诀窍在于,保证返回的ResultSet的字段名称(或标签或别名)和Java Bean中可写入属性的名称匹配

<statement id=”getProduct”resultClass=”com.ibatis.example.Product”>select?PRD_ID asid,?PRD_DESCRIPTION as description?from PRODUCT?where PRD_ID = #value#</statement>

从上面的例子中还是比较容易看明白的,不过要注意的是数据库对大小写是不敏感的,这样的话就可能会出 现些问题了。。
基本类型的Result(即String,Integer,Boolean):基本类型只能有一个属性,名字可以任意取。如:

<resultMapid=”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?fromPRODUCT</statement>


Map类型的Result:如:

<resultMap id=”get-product-result”class=”java.util.HashMap”>

<result property=”id”column=”PRD_ID”/>

<result property=”code” column=”PRD_CODE”/>

<resultproperty=”description” column=”PRD_DESCRIPTION”/>

<resultproperty=”suggestedPrice” column=”PRD_SUGGESTED_PRICE”/>

</resultMap>

或者(隐式的):

<statementid=”getProductCount” resultClass=”java.util.HashMap”>select * fromPRODUCT</statement>


复杂类型的数据:执行的大致顺序已经标出,应该是对的: (2)

<resultMapid=”get-product-result” class=”com.ibatis.example.Product”> ? ? ??????

<result property=”id” column=”PRD_ID”/>??? ??

<resultproperty=”description” column=”PRD_DESCRIPTION”/>??? ??

<resultproperty=”category” column=”PRD_CAT_ID”select=”getCategory”/></resultMap>(4)

<resultMapid=”get-category-result” class=”com.ibatis.example.Category”>?????

<result property=”id” column=”CAT_ID”/>??? ??

<resultproperty=”description” column=”CAT_DESCRIPTION”/></resultMap>(1)

<statement id=”getProduct” parameterClass=”int”resultMap=”get-product-result”>??? ??select * from PRODUCT where PRD_ID =#value#</statement>(3)<statementid=”getCategory” parameterClass=”int” resultMap=”get-category-result”>?????select * from CATEGORY where CAT_ID = #value#</statement>使用一个联合查询和嵌套的属性映射来代替两个查询statement(因为在上面的例子中每次查询都 是要多一次的代价的,要做的是不管查多少次都只多出一次的效果)。如下:

? ?<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” />?? ?

<resultproperty=”category.description” column=”CAT_DESCRIPTION”/></resultMap>
<statement id=”getProduct” parameterClass=”int”resultMap=”get-product-result”>?? ?select *?from PRODUCT, CATEGORY?wherePRD_CAT_ID=CAT_ID?and PRD_ID = #value#</statement>

注:如很少有必要访问相关的对象(如Product对象的Category属性),则不用联合查询加载所有的Categor属性可能更快。
延迟加载 VS 联合查询基本的原则是,如果您需要访问相关的对象,则使用联合查询。否则,使用延迟加载和字节码增强选项的子查询。
复杂类型集合的属性:ResultMap还可以装入代表复杂类型对象集合(List)的属性,用以表示在数据库中相互关系为多对多或一对多的数据。拥有集合属性的类作为“一”的一方,而在 集合中的对象作为“多”的一方。用来装入对象集合的mapped statement和上面例子一样。唯一的不同是,让SQL Map架构装入复杂类型集合(List)的业务对象的属性必须是java.util.Listjava.util.Collection类 型。

? ? ?<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 * fromCATEGORY where CAT_ID = #value#</statement><statementid=”getProductsByCatId” parameterClass=”int” resultMap=”get-product-result”>??? ?select * from PRODUCT where PRD_CAT_ID = #value#</statement>上面一次执行的顺序是3->1->4->2。
组合键值或多个复杂参数属性:在 有多个属性之互相关联的时候就用下面的这种格式:

<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>
缓存MappedStatement结果集Cachemodel是在SQL Map XML文件中定义的可配置缓存模式,可以使用cacheModel元 素来配置。例子如下:

<cacheModel id="product-cache" type ="LRU"readOnly=”true” serialize=”false”>?? ? ?<flushIntervalhours="24"/>?? ? ?<flushOnExecutestatement="insertProduct"/>?? ? ?<flushOnExecutestatement="updateProduct"/>?? ? ?<flushOnExecutestatement="deleteProduct"/>?? ? ?<property name=”cache-size”value=”1000”/>

</cacheModel>

指定mapped statement使用的cache model,例如:

<statement id=”getProductList” cacheModel=”product-cache”>?? ??select * from PRODUCT where PRD_CAT_ID = #value#</statement>
只读 VS 可读写:框架同时支持只读和可读写缓存。
Serializable可读写缓存:
缓 存为每一个Session返回缓存对象不同的实例(复本)。因此每一个Session都可以安全修改返回的对象。不同之处在于,通常您希望从缓存中得到同一个对象,但这种情况下得到的是不同的对象。还有,每一个缓冲在Serializable缓存的对象都必须是Serializable的。这意味着不能同 时使用Serializable缓存和延迟加载,因为延迟加载代理不是Serializable的。想知道如何把Serializable缓存,延迟加载 和联合查询结合起来使用,最好的方法是尝试。要使用Serializable缓存,设置readOnly=“false”和 serialize=“true”。缺省情况下,缓存是只读模式,不使用Serializable缓存。只读缓存不需要Serializable。
缓存类型:CacheModel使用插件方式来支持不同的缓存算法。Cache Model实现的其他配置参数通过cacheModel的property元素来设。其中的四个实现:
MEMORY cache实现使用reference类型来管理cache的行为。垃圾收集器可以根据reference类型判断是否要回收cache中的数据。 MEMORY实现适用于没有统一的对象重用模式的应用,或内存不足的应用。配置如下:

<cacheModelid="product-cache"type="MEMORY">???<flushInterval hours="24"/>?? ?<flushOnExecutestatement="insertProduct"/>?? ?<flushOnExecutestatement="updateProduct"/>?? ?<flushOnExecutestatement="deleteProduct"/>?? ?<property name=”reference-type”value=”WEAK” /></cacheModel>MEMORY cache实现只认识一个<property>元素。这个名为“reference-type”属性的值必须是STRONGSOFTWEAK三者其一。这三个值分别对应于JVM不同的内存reference类型。
LRU Cache实现用“近期最少使用”原则来确定如何从Cache中清除对象。LRU Cache实现可以这样配置:

<cacheModelid="product-cache"type="LRU"><flushIntervalhours="24"/><flushOnExecutestatement="insertProduct"/><flushOnExecutestatement="updateProduct"/><flushOnExecute statement="deleteProduct"/><propertyname=”size” value=”1000”/></cacheModel>
FIFO Cache实现用“先进先出”原则来确定如何从Cache中清除对象。FIFOCache可以这样配置:<cacheModelid="product-cache" type="FIFO"><flushIntervalhours="24"/><flushOnExecutestatement="insertProduct"/><flushOnExecute statement="updateProduct"/><flushOnExecutestatement="deleteProduct"/><property name=”size” value=”1000” /></cacheModel>
OSCACHE Cache实现是OSCache2.0缓存引擎的一个Plugin。它具有高度的可配置性,分布式,高度的灵活性。OSCACHE实现可以这样配 置:<cacheModelid="product-cache" type="OSCACHE"><flushIntervalhours="24"/><flushOnExecutestatement="insertProduct"/><flushOnExecutestatement="updateProduct"/><flushOnExecutestatement="deleteProduct"/></cacheModel>OSCACHE实现不使用property元素, 而是在类路径的根路径中使用标准的oscache.properties文件进行配置。在oscache.properties文件中,您可以配置 Cache的算法(和上面讨论的算法很类似),Cache的大小,持久化方法(内存,文件等)和集群方法。
动态MappedStatement:使用参数值、参数本身和数据列都是动态的SQL,通常非常困难。典型的解决方法是,使用一系列if-else条 件语句和一连串讨厌的字符串连接。对于这个问题,SQL Map API使用和mapped statement非常相似的结构,提供了较为优雅的方法。这里是一个简单的例子:<selectid="dynamicGetAccountList"?cacheModel="account-cache"?resultMap="account-result">select * from ACCOUNT<isGreaterThan prepend="and"property="id" compareValue="0">where ACC_ID =#id#</isGreaterThan>order by ACC_LAST_NAME</select>一个更复杂的例子:<statementid="dynamicGetAccountList" resultMap="account-result" >select* from ACCOUNT<dynamic prepend="WHERE"><isNotNullprepend="AND" property="firstName">(ACC_FIRST_NAME =#firstName#<isNotNull prepend="OR"property="lastName">ACC_LAST_NAME = #lastName#</isNotNull>)</isNotNull><isNotNullprepend="AND" property="emailAddress">ACC_EMAIL like#emailAddress#</isNotNull><isGreaterThan prepend="AND"property="id" compareValue="0">ACC_ID =#id#</isGreaterThan></dynamic>order byACC_LAST_NAME</statement>
二元条件元素prepend - 可被覆盖的SQL语句组成部分,添加在语句的前面(可选)property -被比较的属性(必选)compareProperty - 另一个用于和前者比较的属性(必选或选择compareValue)compareValue - 用于比较的值(必选或选择compareProperty)
一元条件元素一元条件元素检查属性的状态是否符合特定的条件。prepend - 可被覆盖的SQL语句组成部分,添加在语句的前面(可选)property -被比较的属性(必选)
Parameter Present:这些元素检查参数对象是否存在。
Iterate:这属性遍历整个集合,并为List集合中的元素重复元素体的内容。Iterate的属性:prepend -可被覆盖的SQL语句组成部分,添加在语句的前面(可选)property - 类型为java.util.List的用于遍历的元素(必选)open -整个遍历内容体开始的字符串,用于定义括号(可选)close -整个遍历内容体结束的字符串,用于定义括号(可选)conjunction - 每次遍历内容之间的字符串,用于定义AND或OR(可选)
使用SQL Map API编程
配置SQL Map
一 旦您创建了SQL Map XML定义文件和SQL Map配置文件,配置SQL Map就是一件极其简单的事情。SQL Map使用XmlSqlMapClientBuilder来创建。这个类有一个静态方法叫buildSqlMap。方法buildSqlMap简单地用一 个Reader对象为参数,读入sqlMap-config.xml文件(不必是这个文件名)的内容。String resource =“com/ibatis/example/sqlMap-config.xml”;Reader reader =Resources.getResourceAsReader (resource);SqlMapClient sqlMap =SqlMapClientBuilder.buildSqlMap(reader);
事务处理缺省情况下,调用SqlMapClient对象的任意executeXxxx()方法将缺省地自动COMMIT/ROLLBACK。这意味着每次调用executeXxxx()方法都是一个独立的事务。这确实很简单,但对于需要在同一个事务中执行多个语句的情况(即只能同时成功或失败),并不适用。这正是事务处理要关心的事情。如果您在使用Global Transaction(在SQL Map配置文件中设置),您可以使用自动提交并且可以得到在同一事务中执行的效果。但为了提高性能,最好是明确地划分事务的范围,因为这样做可以减少连接池的通讯流量和数据库连接的初始化。
SqlMapClient对象拥有让您定义事务范围的方法。使用下面SqlMapClient类的方法,可以开始、提交和/或回退事务:publicvoid startTransaction () throws SQLExceptionpublic void commitTransaction ()throws SQLExceptionpublic void endTransaction () throws SQLException开始一个事务,意味着您从连接池中得到一个连接,打开它并执行查询和更新SQL操作。使用事务处理的例子如下:
private Reader reader = newResources.getResourceAsReader("com/ibatis/example/sqlMapconfig.xml");privateSqlMapClient sqlMap = XmlSqlMapBuilder.buildSqlMap(reader);publicupdateItemDescription (String itemId, String newDescription) throwsSQLException {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()方法。否则,会用光连接池中的连接并导致死锁。
自动的事务处理虽 然极力推荐使用明确划分的事务范围,在简单需求(通常使只读)的情况下,可以使用简化的语法。如果您没有使用 startTransaction(),commitTransation()和rollbackTransaction()方法来明确地划分事务范围,事务将会自动执行。例如:
private Reader reader = newResources.getResourceAsReader("com/ibatis/example/sqlMapconfig.xml");privateSqlMapClient sqlMap = XmlSqlMapBuilder.buildSqlMap(reader);publicupdateItemDescription (String itemId, String newDescription) throwsSQLException {try {Item item = (Item) sqlMap.queryForObject("getItem", itemId);item.setDescription (“TX1”);//No transaction demarcated, sotransaction will be automatic (implied)sqlMap.update("updateItem", item);item.setDescription(newDescription);item.setDescription (“TX2”);//No transaction demarcated, so transaction willbe automatic (implied)sqlMap.update("updateItem", item);} catch (SQLExceptione) {throw (SQLException) e.fillInStackTrace();}}注意!使 用自动事务处理要非常小心。虽然看起来很有吸引力,但如果有多个数据更新操作要在同一事务中处理时,您会遇到麻烦。在上面的例子中,如果第二个 “updateItem”操作失败,第一个“updateItem”操作仍然会执行,description会更新成“TX1”.
全局(分布式)事务
External/Programmatic Global 事务
要支持外部管理或手工编程管理全局事务,必须在SQL Map配置文件中设定<transactionManager>type属性为EXTERNAL。 使用外部管理的全局事务,SQL Map事务控制方法变得有的多余,因为事务的开始、提交和回退都由外部的事务管理器来控制。但是,使用SqlMapClient的 startTransaction(),commitTransaction()或rollbackTransaction()来划分事务范围(相对于自动的事务处理),还是对提高性能有帮助。继续使用这些方法,可以保持编程规范的一致性。另一个好处是,在某些情况下,您可能需要改变关闭资源的顺序(不幸的是,不同的应用服务器和事务管理器具有不同的规则)。除了这些考虑,要使用全局事务,不需要改变您的SQL Map代码。
受管理的(Managed)全局事务SQL Map框架也可以为您管理全局事务。要支持受管理的全局事务,必须在SQL Map配置文件中设定<transactionManager>type属性为JTA,并设定“UserTransaction”属性为JNDI的全名,以使SqlMapClient实例能找到UserTransaction对象。
使 用全局事务编程,代码没有多大的不同,但有几个小小的地方要注意。例如:try{orderSqlMap.startTransaction();storeSqlMap.startTransaction();orderSqlMap.insertOrder(…);orderSqlMap.updateQuantity(…);storeSqlMap.commitTransaction();orderSqlMap.commitTransaction();}?finally{try {storeSqlMap.endTransaction()}finally {orderSqlMap.endTransaction()}}警告!虽然这些看起来很简单,但记住不要滥用全局(分布式)事务,这点很重要。这样做既 有性能方面的考虑,同时也是因为全局事务会让应用服务器和数据库驱动程序的设置变得更复杂。虽然看起来简单,您可能还是会遇到一些困难。
批处理SQL MapAPI使用批处理很简单,可以使用两个简单的方法划分批处理的边界:sqlMap.startBatch();//…execute statements inbetweensqlMap.executeBatch();当调用endBatch()方法时,所有的批处理语句将通过JDBC Driver来执行。
用SqlMapClient执行SQL语句SqlMapCient类提供了执行所有mapped statement的API。这些方法如下:public intinsert(String statementName,?ObjectparameterObject)?throws SQLExceptionpublic

int update(StringstatementName,?Object parameterObject)?throws SQLExceptionpublic

int delete(StringstatementName,?Object parameterObject)?throws SQLExceptionpublic

Object queryForObject(StringstatementName,?Object parameterObject)?throws SQLExceptionpublic

Object queryForObject(StringstatementName,?Object parameterObject, Object resultObject)?throwsSQLExceptionpublic

List queryForList(StringstatementName,?Object parameterObject)?throws SQLExceptionpublic ListqueryForList(StringstatementName,

Object parameterObject,?int skipResults,int maxResults)?throws SQLExceptionpublic ListqueryForList (StringstatementName,?Object parameterObject, RowHandler rowHandler)?throws SQLExceptionpublic

PaginatedList queryForPaginatedList(StringstatementName,?Object parameterObject, int pageSize)?throws SQLExceptionpublic

Map queryForMap (StringstatementName, Object parameterObject,?String keyProperty)?throwsSQLExceptionpublic

 Map queryForMap(String statementName, Object parameterObject,?String keyProperty, StringvalueProperty)?throws SQLException
代码例子例子1:执行update(insert,update,delete)sqlMap.startTransaction();Productproduct = new Product();product.setId (1);product.setDescription (“ShihTzu”);int rows = sqlMap.insert (“insertProduct”,product);sqlMap.commitTransaction();
例子2:查询成对象 (select)sqlMap.startTransaction();Integerkey = new Integer (1);Product product = (Product)sqlMap.queryForObject(“getProduct”, key);sqlMap.commitTransaction();
例子3:用预赋值的结果对象查询成对象 (select)sqlMap.startTransaction();Customercustomer = new Customer();sqlMap.queryForObject(“getCust”, parameterObject,customer);sqlMap.queryForObject(“getAddr”, parameterObject,customer);sqlMap.commitTransaction();
例子4:查询成对象 List(select)sqlMap.startTransaction();List list= sqlMap.queryForList (“getProductList”, null);sqlMap.commitTransaction();
例子5:自动提交//当没调用startTransaction的情况下,statements会自动提交。//没必要commit/rollback。int rows = sqlMap.insert(“insertProduct”, product);
例 子6:用结果集边界查询成对象List(select)sqlMap.startTransaction();List list= sqlMap.queryForList (“getProductList”, null, 0,40);sqlMap.commitTransaction();
例子7:用RowHandler执行查询(select)public class MyRowHandlerimplements RowHandler {public void handleRow (Object object, List list) throwsSQLException {Product product = (Product) object;product.setQuantity(10000);sqlMap.update (“updateProduct”, product);// Optionally you could addthe result object to the list.// The list is returned from the queryForList()method.}}sqlMap.startTransaction();RowHandler rowHandler = newMyRowHandler();List list = sqlMap.queryForList (“getProductList”, null,rowHandler);sqlMap.commitTransaction();
例子8:查询成Paginated List(select)PaginatedList list=sqlMap.queryForPaginatedList (“getProductList”, null,10);list.nextPage();list.previousPage();
例子 9:查询成Map(select)sqlMap.startTransaction();Map map =sqlMap.queryForMap (“getProductList”, null,“productCode”);sqlMap.commitTransaction();Product p = (Product) map.get(“EST-93”);
在运用中的总结:

上面说的都是细节的东西,很多的人在学习的时候都是可以看到的,放在这里是为了以后方便查下ctrl+F嘛。不过,通过这些细节的学习会发现,在刚开始是在讲各个属性是干嘛用的,在稍微后面的时候就开始纠结怎么用才能使得效率更高一些。不可否认的是,属性的熟悉对我们很重要,但是后面的思想甚至是对数据库的了解才是最重要的,ibaits只不过是对数据库的操作的一个框架而已,我们应该花更多的时间在灵魂上!!感觉ibatis上手还是比较容易的!


原创粉丝点击