iBATIS数据映射器开发者指南

来源:互联网 发布:linux access函数 编辑:程序博客网 时间:2024/06/03 23:41
1、 iBATIS数据映射
1.1  这里涉及的
1.2  免责声明
2、大局
2.1  它是做什么的?
2.2  它如何工作?
2.3  iBATIS是最好的选择我的项目?
3、 处理数据映射
3.1  什么是在数据映射定义文件呢?
3.2  映射语句
3.2.1   声明类型
3.2.2  存储过程
3.2.3  SQL
3.2.4  语句类型元素属性
3.3  参数地图和内联参数
3.3.1。 < parameterMap >属性
3.3.2章。 < parameter >元素
3.3.3。 内联参数地图
3.3.4。 标准类型参数
3 3 5。 地图或IDictionary类型参数
3.4 结果地图
3 4 1  扩展resultMaps
3.4.2  parameterMap属性
3 4 3  隐式结果地图
3.4.4  原始的结果(即。字符串、整数、Boolean)
3 4 5 地图ResultMaps
3 4 6  复杂的属性
3 4 7  避免N + 1选择(1:1)
3 4 8  复杂集合属性
3 4 9  避免N + 1选择(1:M和M:N)
3 4 10  组合键或多个复杂的参数属性
3.5  支持的类型参数地图和结果地图
3 5 1
3.5.2
3.6  支持数据库类型参数地图和结果地图
3.6.1 操作
3.7  缓存模型
3.7.1  只读和读/写(Java只有)
3.7.2  缓存类型
3.7.3
3 7 4 LRU
3 7 5 FIFO
3.8  动态SQL
3 8 1  二进制条件元素
3 8 2 一元的条件元素
3 8 3  简单的动态SQL元素
4、 Java开发人员指南
4.1  iBATIS数据映射为Java安装
4.4.1  JAR文件和依赖关系
4 1 2  从版本1.x 升级到版本2. x
4.2  配置数据映射为Java
4 2 1  数据映射器客户
4.2.2  数据映射器配置文件(SqlMapConfig.xml)
4.2.3  数据映射器配置元素
4.3  编程和iBATIS数据映射器:Java API
4.3.1  配置
4.3.2  交易
4.3.3  全球(分布式)事务
4.3.4  批次(Java只有)
4 3 5  通过SqlMapClient API执行语句
4.4  一个页面的JavaBeans课程
4.5  日志SqlMap活动与Jakarta Commons日志
4.5.1  日志配置
4.6  SimpleDataSource(com ibatis common jdbc . *)
4.7  ScriptRunner(com ibatis common jdbc . *)
4.8  资源(com ibatiscommon*)
5、 净开发者指南
5.1  安装数据映射为。net
5.1.1  设置分布
5.1.2  添加程序集引用
5.1.3  添加XML文件条目
5.2 配置数据映射为 .net
5 2 1  数据映射器客户
5.2.2  数据映射器配置文件(SqlMapper.config)
5 2 3  数据映射器配置元素
5.3  编程和iBATIS数据映射器:。 净API
5 3 1  构建一个SqlMapper实例
5 3 2  探索SqlMapper API
5 3 3  使用显式的和自动交易
5 3 4  编码示例[TODO:扩大在一个食谱的实际例子)
5.4  日志SqlMap活动与Apache Log4Net
5.4.1  日志配置

1。 一个iBATIS数据映射

iBATIS数据映射框架使它更容易使用一个数据库和一个Java或 .NET应用程序。 iBATIS数据映射器夫妇对象与存储过程或SQL语句使用一个XML描述符。 简约最大的优势就是iBATIS数据映射器在对象关系映射工具。 使用iBATIS数据映射器你依靠自己的对象、XML和SQL。 几乎没有学习,你不知道。 iBATIS数据映射器你与的全部能力包括SQL和存储过程在你的指尖。

1.1。 这里所讨论的是什么

本指南涵盖了Java和iBATIS数据映射的净实现。

iBATIS数据映射为Java版本2. xiBATIS数据映射为。 净版本1. x

因为iBATIS依赖于一个XML描述符来创建映射,大部分材料同时适用于实现。 当一个部分属于只有一个实现,它被标记为“Java只有”或“。 净只有”。 如果你不使用该实现,你可以放心地跳过这部分。 (别担心,伙计。)

有关安装指南,请参阅Java或。 网络开发者指南(部分4和5)。

一个教程也是可用的。 我们建议为您的平台回顾本教程之前,阅读本指南。

1 2一个免责声明

iBATIS毫无保证,明示或暗示在这个文档的信息。 实际公司的名字和产品这里提到的可能是他们的各自的主人的商标。

2。 一个大局

iBATIS是一个简单但完整的框架,可以让您映射对象到你的SQL语句或存储过程。 iBATIS框架的目标是获得80%的数据访问功能只使用20%的代码。

2.1。 一个有什么功能?

开发人员常常创建对象之间的映射在一个应用程序。 一个定义的映射是一个“对象,设置两个独立的对象之间的通信。 “一个数据映射器是一个“层之间移动数据对象映射器,和一个数据库,同时让他们相互独立的和映射器本身。 “[模式的企业架构,ISBN 0-321-12742-0]。

你提供数据库和对象;iBATIS提供映射层,是两个人之间的。

2.2。 一个它如何工作?

你的编程平台已经提供了一个能够访问数据库库,无论是通过SQL语句或存储过程。 但是开发人员发现一些事情仍然很难做好当使用JDBC或ADO“股票”。 净,包括:

从编程代码分离SQL代码通过输入参数库类和提取输出分离数据访问类从业务逻辑类缓存常用数据,直到它的变化管理事务和线程

iBATIS数据映射器解决这些问题——以及更多——通过使用XML文件来创建一个普通之间的映射对象和一个SQL语句或存储过程。 “普通对象”可以是一个地图或JavaBean(如果您使用的是Java)或一个IDictionary或属性对象(如果您使用的是. net)。

提示

对象不需要一个特殊的对象层次结构的一部分或实现特殊的接口。 (这就是为什么我们称之为“普通”对象)。 无论你正在使用应该很好地工作。

图1的图表iBATIS工作流。

FigureA 1。 一个iBATIS数据映射器工作流

iBATIS Data Mapper workflow

这是一个高水平的描述说明了工作流由图1:

  1. 提供一个参数,或者作为一个对象或者一个本地类型。 这个参数可用于设置运行时的值在您的SQL语句或存储过程。 如果一个运行时的值是不需要的,参数可以省略。

  2. 执行映射通过参数和名字你给声明或程序在XML描述符。 在这一步中,奇妙的事情发生。 该框架将准备SQL语句或存储过程,设置任何运行时使用你的参数值,执行程序或声明,并返回结果。

  3. 在执行更新的情况下,返回的行数。 对于一个查询,单个对象,或者返回一个对象集合。 像参数,结果对象或对象集合,可以是一个普通对象或一个本地类型。 结果也可以作为XML(Java只)。

所以,什么看起来像在源代码? 这里是你如何可能的代码插入一个“lineItem”对象到你的数据库:

Mapper.instance().insert("insertLineItem",lineItem); // Java

如果你的数据库生成的主键,生成的键可以从相同的方法调用返回,就像这样:

MyKey = Mapper.Instance().Insert("InsertLineItem",lineItem); // .NET

示例1展示了一个XML描述符为“InsertLineItem”。

ExampleA 1。 一个“InsertLineItem”描述符

  <insert id="InsertLineItem" parameterClass="LineItem">  INSERT INTO [LinesItem]   (Order_Id, LineItem_LineNum, Item_Id, LineItem_Quantity, LineItem_UnitPrice)  VALUES  (#Order.Id#, #LineNumber#, #Item.Id#, #Quantity#, #Item.ListPrice#)  <selectKey resultClass="int" keyProperty="id" >    SELECT @@IDENTITY AS ID  </selectKey>  </insert>

< selectKey >节返回一个自动生成的键从一个SQL Server数据库(例如)。

如果您需要选择多个行,iBATIS可以返回对象的列表,每个映射到一个结果集行:

IList productList = Mapper.Instance().QueryForList("selectProduct",categoryKey); // .NET

或者只是一个,如果这是你所需要的:

Object product = Mapper.instance().queryForObject("selectProduct",productKey); // Java

当然,还有更多,但这是iBATIS从10000米。 (更长、更温和的介绍,请参阅本教程)。 第三节描述了数据映射定义文件,该声明为“InsertLineItem”将被定义。 为您的平台的开发者指南(部分4或5)描述了“引导”配置文件,暴露了iBATIS应用程序。

2.3。 一个是iBATIS的最佳选择我的项目?

iBATIS是一种数据映射工具。 它的作用是将列映射的一个数据库查询(包括一个存储过程)到一个对象的属性。 如果您的应用程序是基于业务对象(包括地图或IDictionary对象),然后iBATIS可以是一个不错的选择。 iBATIS是一个甚至更好的选择当你的应用程序分层,这样,业务层不同于用户界面层。

在这种情况下,另一个不错的选择将一个对象/关系映射工具(或/ M工具),像Hibernate或NHibernate。 (其他这一类产品是Apache ObjectRelationalBridge和Gentle.NET)。 一个或/ M工具生成所有或大部分的SQL,或者在运行时提前。 这些产品被称为或/ M工具,因为他们试图映射对象图到关系模式。

iBATIS不是一个或/ M工具。 iBATIS可以帮助你对象映射到存储过程或SQL语句。 底层的模式是无关紧要的。 一个或/ M工具是伟大的,如果你可以映射到表对象。 但他们并不是很伟大的如果你的对象被存储为一个关系视图,而不是作为一个表。 如果你可以编写一个语句或过程,揭示了你的对象的列,不管他们是如何存储,iBATIS可以休息。

所以,你如何决定是否或/ M到DataMap吗? 一如既往,最好的建议是实现一个代表你的项目的一部分使用何种方法,然后决定。 但是,一般来说,或/ M是一件好事,当你

1。 可以完全控制您的数据库实现吗

2。 没有一个数据库管理员或SQL大师的团队吗

3。 需要模型问题域之外的数据库作为一个对象图。

同样,最好的时间使用一个数据映射器,比如IBATIS,是当:

1。 你有完全控制数据库实现,或想继续访问遗留数据库,因为它是被重构。

2。 你有数据库管理员或SQL大师的团队。

3。 数据库是被用于模型问题域和应用程序的主要作用是帮助客户端使用的数据库模型。

最后,必须决定什么是最好的项目。 如果一个或/ M的工具为你工作的更好,那太好了! 如果你的下一个项目有不同的需求,那么我们希望你给iBATIS再看一看。 如果iBATIS适合你现在:太棒了! 顺便支持论坛,如果你有任何问题。

3。 一个处理数据映射

如果你想知道如何配置和安装iBATIS,看到开发者指南为您的平台(部分4或5)。但是如果你想知道iBATIS真的工作,继续在这里。

数据映射定义文件是令人感兴趣的东西出现。 在这里,您定义应用程序如何与您的数据库。 正如前面提到的,数据映射定义一个XML描述符文件。 通过使用一个服务程序提供了iBATIS,XML描述符渲染成一个客户端对象(或“映射”)。 访问你的数据地图,您的应用程序调用客户端对象,并通过在声明的名字你需要。

真正的工作使用iBATIS与其说是在应用程序代码中,但在XML描述符,iBATIS呈现。 而不是东与应用程序的源代码,你的猴子用XML描述符相反。 好处是,XML描述符更加适合你的对象属性的任务映射到数据库实体。 至少,这是我们自己的经验和我们自己的应用程序。 当然,你的里程可能有所不同。

3.1。 是什么在数据映射定义文件呢?

如果你阅读本教程中,您已经看到了一些简单的数据映射的例子,像一个示例2中显示的。

ExampleA 2。 一个简单的数据图(. net)

<?xml version="1.0" encoding="UTF-8" ?><sqlMap namespace="LineItem" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:noNamespaceSchemaLocation="http://ibatisnet.sf.net/schemaV1/SqlMap.xsd"> <alias>  <typeAlias alias="LineItem" assembly="NPetshop.Domain.dll"   type="NPetshop.Domain.Billing.LineItem" /> </alias> <statements>  <insert id="InsertLineItem" parameterClass="LineItem">  INSERT INTO [LinesItem]   (Order_Id, LineItem_LineNum, Item_Id, LineItem_Quantity, LineItem_UnitPrice)  VALUES  (#Order.Id#, #LineNumber#, #Item.Id#, #Quantity#, #Item.ListPrice#)  </insert></statements></sqlMap>

这张地图需要一些属性从一个LineItem实例和合并到SQL语句的值。 其附加值是我们的SQL在脱离我们的程序代码,我们可以通过我们的LineItem实例直接向图书馆法:

Mapper.Instance().Insert("InsertLineItem",lineItem); // C#

没有大惊小怪,没有混乱。 同样地,看到示例3为一个简单的select语句。

ExampleA 3。 一个简单的数据地图(Java)

<?xml version="1.0" encoding="UTF-8" ?><sqlMap namespace=”Product”><select id=”selectProduct”   parameterClass=”com.ibatis.example.Product”   resultClass=”com.ibatis.example.Product”>  select  PRD_ID as id,  PRD_DESCRIPTION as description  from PRODUCT  where PRD_ID = #id#</select></sqlMap>

在示例3中,我们使用SQL别名映射到我们的对象属性的列和一个iBATIS内联参数(参见侧栏)插入一个运行时的值。 简单派。

但是,如果你想要一些冰淇淋和蛋糕吗? 也许一个樱桃上吗? 如果我们想要缓存结果的选择吗? 或者,如果我们不想使用SQL别名或命名参数。 (说,因为我们正在使用已存在的SQL,我们不想碰。) 示例4显示一个数据图,用于指定一个缓存,并使用一个< parameterMap >和< resultMap >来保持我们的SQL原始。

ExampleA 4。 一个数据映射定义文件和一些花哨的功能(Java)

<?xml version="1.0" encoding="UTF-8" ?><sqlMap namespace=”Product”><typeAlias alias=”product” type=”com.ibatis.example.Product” /><cacheModel id=”productCache” type=”LRU”>  <flushInterval hours=”24”/>  <property name=”size” value=”1000” /></cacheModel><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” cacheModel="productCache">  select * from PRODUCT where PRD_ID = ?</select></sqlMap>

在例4中,< parameterMap >映射SQL”? “产品id属性。 < resultMap >地图列到我们的对象属性。 < cacheModel >使结果过去一千年的这些查询在活跃的记忆长达24小时。

示例4是长和复杂示例3,但是考虑到你所得到的回报,这似乎是一个公平的贸易。 (一个交易甚至。)

很多“敏捷”开发人员将从类似示例3和添加功能,比如缓存之后。 如果你改变了数据地图从示例3到示例4,你就不会碰你的应用程序源代码在所有。 你可以开始简单并添加复杂性只有当它是必要的。

一个单独的数据映射定义文件可以包含许多缓存模型,类型别名,结果地图、参数映射和映射语句(包括存储过程),就像你们。 一切都是加载到相同的配置,所以你可以定义一个数据图中的元素,然后使用它们在另一个。 使用自由裁量权和组织语句和地图为适合您的应用程序通过寻找一些逻辑方式来组织它们。

3.2。 一个映射语句

映射语句可以容纳任何SQL语句,可以使用参数地图和地图为输入和输出结果。 (一个存储过程的一个特殊形式的声明。 看到第3.2.1节和3.2.2更多。)

如果这个案子很简单,映射的语句可以引用参数和结果类直接。 映射语句支持缓存通过引用一个缓存模型元素。 示例5显示的语法声明元素。

ExampleA 5。 一个声明元素的语法

<statement id=”statementName”  [parameterMap=”nameOfParameterMap”]  [parameterClass=”some.class.Name”]  [resultMap=”nameOfResultMap”]  [resultClass=”some.class.Name”]  [cacheModel=”nameOfCache”]  [xmlResultName="nameOfResult”] (Java only)>   select * from PRODUCT where PRD_ID = [?|#propertyName#]   order by [$simpleDynamic$]</statement>

在示例5,[括号]部分是可选的,和一些选项是相互排斥的。 这是完全合法的,有一个映射声明简单示例所示6。

ExampleA 6。 一个简单的映射语句

<statement id=”insertTestProduct” >  insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (1, “Shih Tzu”)</statement>

例6显然是不可能的,除非你正在运行一个测试。 但它确实表明,您可以使用iBATIS执行任意SQL语句。 更有可能的是,您将使用对象映射特性与参数地图(3.4节)和结果地图(3.5节),奇妙的事情发生。

3.2.1之上。 一个声明类型

<声明>元素是一个普遍的一个€œ赶上真主安拉€元素,可用于任何类型的SQL语句。 通常这是一个好主意,使用一种更具体的语句类型的元素。 更具体的元素提供了更好的错误检查,甚至更多的功能。 (例如,插入语句可以返回一个数据库生成的关键。) 表1总结了语句类型元素及其支持的属性和特性。

为多1。 一个六语句类型的元素

声明元素属性子元素方法<声明>
id parameterClass resultClass parameterMap resultMap cacheModel xmlResultName (Java only)
All dynamic elements
insert update delete All query methods
< insert >
id parameterClass parameterMap
All dynamic elements<selectKey> <generate> (.NET only)
insert update delete 
< update >
id parameterClass parameterMap
All dynamic elements <generate>  (.NET only)
insert update delete
<删除>
id parameterClass parameterMap
All dynamic elements <generate>  (.NET only)
insert update delete
< select >
id parameterClass resultClass parameterMap resultMap cacheModel
All dynamic elements <generate> (.NET only)
All query methods
<程序>
id parameterClass resultClass parameterMap resultMap xmlResultName (Java only)
All dynamic elements 
insert update delete All query methods

使用的各种属性声明类型的元素都包含在部分3.2.4条。

第3.2.2章。 一个存储过程

iBATIS数据映射器将存储过程作为另一个语句类型。 例7显示了一个简单的数据地图托管一个存储过程。

ExampleA 7。 一个数据地图使用存储过程

<!-- Java --><parameterMap id="swapParameters" class="Map" >  <parameter property="email1" jdbcType="VARCHAR" javaType="java.lang.String" mode="INOUT"/>  <parameter property="email2" jdbcType="VARCHAR" javaType="java.lang.String" mode="INOUT"/></parameterMap> ...<procedure id="swapEmailAddresses" parameterMap="swapParameters" >  {call swap_email_address (?, ?)}</procedure><!-- .NET --><procedure id="SwapEmailAddresses" parameterMap="swap-params">  ps_swap_email_address</procedure> ... <parameterMap id="swap-params">  <parameter property="email1" column="First_Email" />  <parameter property="email2" column="Second_Email" /></parameterMap>

例7背后的想法是,调用存储过程的“swapEmailAddress”将交换两个电子邮件地址在两个列在一个数据库表和还在参数对象。 (在这里,一个地图或HashTable)。 这个参数对象只是修改如果参数映射模式属性设置为一个€œINOUTa€或€œ一€。 否则他们保持不变。 当然,不可变参数对象(例如,String)不能被修改。

注意

对于Java,总是要确保使用标准的JDBC存储过程的语法。 看到JDBC CallableStatement文档了解详细信息。

对。 净,parameterMap属性是必需的。 这个DBType、参数方向和大小都是这里用处不大的框架(通过CommandBuilder)。

第3.2.3。 一个SQL

如果你不使用存储过程,最重要的部分是SQL语句类型的元素。 您可以使用任何SQL语句,为您的数据库系统是有效的。 因为iBATIS SQL传递到标准库(JDBC或者ADO.NET),您可以使用任何声明,您可以使用与iBATIS没有iBATIS。 你可以使用任何数据库系统支持功能,甚至发送多个语句,只要你的驱动或提供者支持他们。

如果标准,静态SQL并不够,iBATIS可以帮助你建立一个动态SQL语句。 参见3.7节了解更多的动态SQL。

3 2 3 1。 一个转义XML符号

因为你是结合SQL和XML在单个文档,会发生冲突。 最常见的冲突是大于和小于号(<)>。 SQL语句使用这些符号作为操作符,但是他们保留符号在XML。 一个简单的解决方案是“逃离”的SQL语句,使用XML保留在一个CDATA元素符号。 示例8演示了。

ExampleA 8。 一个使用CDATA“逃”的SQL代码

<statement        id="selectPersonsByAge" parameterClass=”int” resultClass="person">        <![CDATA[ SELECT * FROM PERSON WHERE AGE > #value# ]]>        </statement>
3 2 3 2。 一个自动生成的键

许多数据库系统支持自动生成的主键字段,如供应商扩展。 有些供应商提前生成密钥(如。甲骨文),一些供应商邮报生成密钥(如服务器和MySQL。sql女士)。 在这两种情况下,您可以获得一个预先生成键使用一个< selectKey >节在一个< insert >元素。 示例9显示了一个< insert >语句要么方法。

ExampleA 9。 一个< insert >语句使用< selectKey >节

<!—Oracle SEQUENCE Example --> <insert id="insertProduct-ORACLE"        parameterClass="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="product"> insert into PRODUCT (PRD_DESCRIPTION)        values (#description#) <selectKey resultClass="int"        keyProperty="id" > SELECT @@IDENTITY AS ID </selectKey>        </insert><!-- MySQL Example -->[:TODO:]
3 2 3 3。 一个<生成>标记(。 净只有)

您可以使用iBATIS SQL语句执行任何应用程序需要。 当要求很简单、明显的一份声明中,你可能不需要编写一个SQL语句在所有。 <生成>标记可用于创建简单的SQL语句自动,基于一个< parameterMap >元素。 这四个CRUD语句类型(插入、选择、更新和删除)都受支持。 对于一个选择,你可以选择所有或选择由一个键(或键)。 例10显示了一个示例生成的CRUD语句通常的数组。

ExampleA 10。 一个创建“惯常嫌犯”用<生成>标记

<parameterMaps>  <parameterMap id="insert-generate-params">    <parameter property="Name" column="Category_Name"/>    <parameter property="Guid" column="Category_Guid" dbType="UniqueIdentifier"/>      <!--Guid for Oledb, UniqueIdentifier for SqlClient, Odbc -->  </parameterMap>  <parameterMap id="update-generate-params" extends="insert-generate-params">    <parameter property="Id" column="Category_Id" />  </parameterMap>  <parameterMap id="delete-generate-params">   <parameter property="Id" column="Category_Id" />   <parameter property="Name" column="Category_Name"/>  </parameterMap>  <parameterMap id="select-generate-params">   <parameter property="Id" column="Category_Id" />   <parameter property="Name" column="Category_Name"/>   <parameter property="Guid" column="Category_Guid" dbType="UniqueIdentifier"/>  </parameterMap></parameterMaps><statements><update id="UpdateCategoryGenerate" parameterMap="update-generate-params"> <generate table="Categories" by="Category_Id"/></update><delete id="DeleteCategoryGenerate" parameterMap="delete-generate-params"> <generate table="Categories" by="Category_Id, Category_Name"/></delete><select id="SelectByPKCategoryGenerate" resultClass="Category" parameterClass="Category" parameterMap="select-generate-params">  <generate table="Categories" by="Category_Id"/> </select><select id="SelectAllCategoryGenerate" resultClass="Category" parameterMap="select-generate-params"> <generate table="Categories" /> </select><insert id="InsertCategoryGenerate" parameterMap="insert-generate-params"> <selectKey property="Id" type="post" resultClass="int">  select CAST(@@IDENTITY as int) as value </selectKey> <generate table="Categories" /></insert></statements>

注意

生成的SQL是当数据映射器实例构建,所以没有性能影响在执行时间。

标记生成ANSI SQL,这应该适用于任何兼容的数据库。 特殊类型,如blob、不受支持,并且特定于供应商的类型也不支持。 但是,生成标记并保持简单的事情变得简单。

重要

的计划使用<生成>标记是拯救开发商麻烦的编码平凡的SQL语句(和只有平凡的语句)。 这并不意味着作为一个对象到关系的映射工具。 有许多框架,提供广泛的对象到关系的映射功能。 <生成>标签并不能代替的。 当<生成>标签并不适合你的需要,使用常规声明相反。

3 2 3 3 1。 一个<生成>标记的属性

生成标记支持两个属性:表和通过。

——所需的表属性指定了表名使用的SQL语句

通过——可选属性指定的列中使用WHERE子句。

第3.2.4章。 一个语句类型元素属性

六个语句类型元素采取各种属性。 看到第3.2.1节表的每个元素类型的列属性接受。 单个属性中描述了部分3 2 4 1通过3 2 4 7。

3 2 4 1一个id

所需的ID属性提供了一个名称为这个语句,它必须是唯一的在这个< SqlMap >。

3 2 4 2 a parameterMap

一个参数映射定义值的有序列表,配合”? “占位符的一个标准,参数化的查询语句。 例10显示了< parameterMap >和一个相应的<声明>。

ExampleA 11。 一个一个parameterMap和相应的语句

<parameterMap id=”insert-product-param” class=”product”>  <parameter property=”id”/>  <parameter property=”description”/></parameterMap><statement id=”insertProduct” parameterMap=”insert-product-param”>  insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (?,?);</statement>

在范例11中,参数图描述了两个参数,以匹配,在秩序,两个SQL语句中的占位符。 第一个一个€œ吗? 一个€替换为价值的ID财产。 第二个是取代描述财产。

iBATIS还支持命名,内联参数,大多数开发人员似乎更喜欢。 然而,参数地图是有用,当SQL必须保存在一个标准形式或当需要提供额外的信息。 更多关于参数地图见3.4节。

3 2 4 3 a parameterClass

如果没有指定parameterMap属性(参见节3 2 4 2),您可以指定一个parameterClass相反和使用内联参数(参见部分3.3.3)。 parameterClass属性的值可以是一个类型别名或者一个类的完全限定名。 例12显示了一个语句使用完全限定的名称和一个别名。

ExampleA 12。 一个方法来指定一个parameterClass

<!-- fully qualified classname (Java) --><statement id=”statementName” parameterClass=”examples.domain.Product”>  insert into PRODUCT values (#id#, #description#, #price#)</statement><!-- typeAlias (defined elsewhere) --><statement id=”statementName” parameterClass=”product”>  insert into PRODUCT values (#id#, #description#, #price#)</statement>
3 2 4 4 a resultMap

结果映射允许您控制如何提取数据从一个查询的结果,以及列映射到对象属性。 例13显示了一个< resultMap >元素和一个相应的<声明>元素。

ExampleA 13。 一个< resultMap >和相应的<声明>

<resultMap id=”select-product-result” class=”product”>  <result property=”id” column=”PRD_ID”/>  <result property=”description” column=”PRD_DESCRIPTION”/></resultMap><statement id=”selectProduct” resultMap=”select-product-result”>  select * from PRODUCT</statement>

在示例13,SQL查询的结果将被映射到产品类的一个实例使用“select产品结果”< resultMap >。 < resultMap >说来填充ID产权prd id列,来填充描述产权prd描述列。

提示

在示例13,注意,使用一个€œselect *一个€是支持的。 如果你想要的所有列,您不需要将它们映射所有单独。 (尽管许多开发人员考虑的一个很好的实践总是指定列预期。)

更多关于结果映射,请参见第3.4节。

3 2 4 5 a resultClass

如果一个resultMap没有指定,您可以指定一个resultClass相反。 resultClass属性的值可以是一个类型别名或者一个类的完全限定名。 指定的类将自动映射到列的结果,基于结果的元数据。 例14展示了一个<声明>元素,该元素有一个resultClass属性。

ExampleA 14。 一个<声明>元素resultClass属性

<statement id="selectPerson" parameterClass=”int” resultClass="person">  SELECT  ER_ID as id,  PER_FIRST_NAME as firstName,  PER_LAST_NAME as lastName,  PER_BIRTH_DATE as birthDate,  PER_WEIGHT_KG as weightInKilograms,  PER_HEIGHT_M as heightInMeters  FROM PERSON  WHERE PER_ID = #value#</statement>

在示例14,Person类属性包括:id,firstName,lastName,出生年月日,weightInKilograms和heightInMeters。 每一种符合列别名所描述的SQL select语句(使用一个€œasa€关键字一个€“标准的SQL特性)。 在执行时,一个人化和填充对象时,通过匹配对象属性的名称(别名)列名称从查询。

使用SQL别名映射的列属性保存定义一个< parameterMap >元素,但也有局限性。 没有方法来指定输出列的类型(如果需要),没有方法来自动加载相关数据(复杂的属性),并且有一个轻微的性能结果(访问结果的元数据)。 在架构上,使用别名这种方式混合”数据库逻辑“与”报告逻辑”,使查询更难阅读和维护。 你可以克服这些限制与一个显式的结果地图(3.4节)。

3 2 4 6一个cacheModel

如果你想要缓存查询的结果,您可以指定一个缓存模型作为<声明>元素。 例15展示了一个< cacheModel >元素和一个相应的<声明>。

ExampleA 15。 一个< cacheModel >元素和其相应的<声明>

<cacheModel id="product-cache" implementation="LRU">  <flushInterval hours="24"/>  <flushOnExecute statement="insertProduct"/>  <flushOnExecute statement="updateProduct"/>  <flushOnExecute statement="deleteProduct"/>  <property name=”size” value=”1000” /></cacheModel><statement id=”selectProductList” parameterClass=”int” cacheModel=”product-cache”>  select * from PRODUCT where PRD_CAT_ID = #value#</statement>

在示例15,缓存被定义为产品使用LRU引用类型和冲每24小时或update语句的执行相关联时。 更多关于缓存模型,请参见第3.6节。

3 2 4 7。 一个xmlResultName(Java只有)

如果你喜欢返回结果作为XML,您可以使用XMLResultName封装元素指定。 例16展示了一个<选择>,指定了一个xmlResultName。

ExampleA 16。 一个< select >元素< xmlResultName >属性

<select id="selectPerson" parameterClass=”int” resultClass="xml" xmlResultName=”person”>  SELECT  ER_ID as id,  PER_FIRST_NAME as firstName,  PER_LAST_NAME as lastName,  PER_BIRTH_DATE as birthDate,  PER_WEIGHT_KG as weightInKilograms,  PER_HEIGHT_M as heightInMeters, only one of which is required  FROM PERSON  WHERE PER_ID = #value#</select>

示例17展示了一个XML对象,可能返回的< select >声明所示示例16。

ExampleA 17。 一个结果XML对象

<person>  <id>1</id>  <firstName>Clinton</firstName>  <lastName>Begin</lastName>  <birthDate>1900-01-01</birthDate>  <weightInKilograms>89</weightInKilograms>  <heightInMeters>1.77</height></person>

3.3。 一个参数地图和内联参数

大多数SQL语句是非常有用的,因为我们可以在运行时传递值。 有人想要一个数据库记录ID 42,我们需要合并,ID号进入一个select语句。 两个JDBC和ADO。 净支持使用问号(?)作为可替换参数。 一个列表的一个或多个参数在运行时传递,并且每个占位符替换反过来。 简单,但劳动密集型的,因为开发人员花了很多时间计算符号,以确保一切都是同步的。

注意

部分3.0和3.1.2介绍iBATIS内联参数,自动映射属性来命名参数。 许多(如果不是大多数,iBATIS开发者喜欢这种方法。 但其他人做更愿意坚持标准,匿名方法,SQL参数。 有时人们需要保持纯洁的SQL语句,其他时候因为额外的信息需要被传递。

一个参数映射定义了一个有序的值的列表匹配的参数化查询语句的占位符。 而属性指定的地图还需要以正确的顺序,每个参数命名。 你可以填充底层类以任何顺序和参数映射确保每个值是通过以正确的顺序。

注意

动态映射语句(3.7节)不能使用参数映射。 被动态、参数的数量将会改变和击败一个参数映射的目的。

参数映射可以提供作为一个外部元素和“内联”。 例18显示了一个外部参数映射。

ExampleA 18。 一个外部参数映射

<!-- Java --><parameterMap id=”parameterMapName” [class=”className”]>[type=”String”]  <parameter property =”propertyName” [jdbcType=”VARCHAR”] [javaType=”String”]    [nullValue=”NUMERIC”] [null=”-9999”]/>  <parameter …… />  <parameter …… /></parameterMap><!-- .NET --><parameterMap id=”parameterMapName” [class=”className”]>  <parameter property =”propertyName” [dbType=”VARCHAR”]     [nullValue=”NUMERIC”] [null=”-9999”] [column="columnName"] [extends=”parent-parameterMap”]/>  <parameter …… />  <parameter …… /> </parameterMap>

在示例18,部分在[方括号]是可选的。 只需要的parameterMap元素ID属性。 这个属性是可选的,但是建议。 这个属性有助于验证传入的参数和优化性能。 例19显示了一个典型的< parameterMap >。

ExampleA 19。 一个典型的< parameterMap >元素

<parameterMap id=”insert-product-param” class=”product”>  <parameter property=”description” />  <parameter property=”id”/></parameterMap><statement id=”insertProduct” parameterMap=”insert-product-param”>  insert into PRODUCT (PRD_DESCRIPTION, PRD_ID) values (?,?);</statement>

注意

参数映射的名字总是本地数据映射定义文件,它们定义。 你可以引用一个参数映射在另一个数据映射定义文件的前缀ID地图的参数与名称空间的数据地图(设置在< sqlMap >根标记)。 如果参数映射在示例是在一个数据图18名为“产品”,它可以引用从另一个文件使用€œProduct.insert-product-parama€。

3.3.1。 一个< parameterMap >属性

< parameterMap >元素接受两个属性:id(要求)和类(可选)。

3 3 1 1一个id

所需的id属性提供了一个独一无二的标识符< parameterMap >在这个数据地图。

3 1 2 3类

可选的属性指定一个对象类来使用这个< parameterMap >。 完整的类名和别名必须被指定。 可以使用任何类。

注意

该参数必须是一个JavaBean类或地图实例(如果您使用的是Java),或者一个属性对象或IDictionary实例(如果您使用的是. net)。

3.3.2章。 一个< parameter >元素

< parameterMap >元素包含一个或多个参数,地图对象属性节占位符在一个SQL语句。 部分3 3 2 1通过3 3 2 11描述每个属性。

3 3 2 1。 一个列(。 净只有)

这个属性可以被设置为一个参数的名称在一个存储过程。

3 3 2 2。 一个方向(。 净只有)

这个方向属性可以被设置为显示一个存储过程参数类型。

输入- handlder输出-输出只输入输出——双向
3 3 2 3。 一个扩展(。 净只有)

可选的延伸属性可以设置为另一个parameterMap的名字在基础这parameterMap。 所有属性的“超级”将包括parameterMap作为这个parameterMap和值从“超级”parameterMap设置在任何指定的值由这个parameterMap。 其效果是类似于扩展类。

3 3 2 4。 一个将javaType(Java只有)

这个将javaType属性用于显式地指定Java属性类型的参数设置。通常这可以来自一个JavaBean属性通过反射,但某些映射如地图和XML映射不能提供类型的框架。 如果将javaType没有设置和框架无法确定类型,这个类型是假定为对象。

3 3 2 5。 一个jdbcType | dbType

这个jdbcType属性(Java)或dbtype属性(. net)用于显式地指定数据库列类型的参数是由这个属性。 对于特定的操作,一些JDBC驱动程序和ADO。 网络提供商不能够确定一个列的类型,必须指定的类型。

注意

一个例子就是Java PreparedStatement方法。 这种方法需要指定的类型。 有些司机将允许类型是隐式只需发送类型其他类型空。 然而,这种行为是不一致的,有些司机需要确切的类型指定。 对于这种情况,iBATIS数据映射器API允许指定类型使用jdbcType属性的parameterMap属性元素。

这个属性是通常只要求如果列是可以为空。 虽然,另一个原因要使用type属性是显式地指定日期类型。 而Java和。 净只有一个日期值类型(java util日期系统datetime),大多数SQL数据库都有不止一个。 通常,一个数据库有至少三种不同的类型(日期,DATETIME,时间戳)。 为了正确的值映射,您可能需要指定列类型,

注意

大多数司机/提供者只需要类型指定为可空的列。 在这种情况下,您只需要指定类型的列,可以为空。

注意

当使用Oracle,您将创建一个一个€œ无效列typea€错误如果试图将一个null值到一个列不指定它的类型。

这个jdbcType属性可以设置为任何字符串值相匹配的常数在JDBC类型类。 虽然它可以设置为任何这些,一些类型不支持(如blob)。 3.5节描述类型所支持的框架。

3 3 2 6。 一个模式(Java只有)

TODO:

3 3 2 7 a nullValue

这个nullValue属性可以设置为任何有效的值(基于属性类型)。 这个nullValue属性用来指定一个外向null值替换。 这意味着,当检测到的值是在对象属性,一个NULL将写入到数据库(相反的行为的一个入站NULL值替换)。 这允许您使用一个€œ很€null号码在您的应用程序的类型不支持null值(比如int,,)。 当这些类型的属性包含一个匹配的null值(比如,一个€“9999),一个null将被写入数据库而不是价值。

3 3 2 8。 一个精密(。 净只有)

精度属性是用来设置最大数量的数字用来表示属性值。

3 3 2 9一个属性

property属性的< parameterMap >是一个对象属性的名称(get方法)的参数对象。 它也可能是一个条目的名称在地图(Java)或IDictionary(. net)。 可以使用这个名字不止一次的次数取决于需要在声明中说。 (在一个更新,您可能将一个列设这也是部分的where子句)。

3 3 2 10。 一个规模(。 净只有)

属性集规模的小数的地方用来解决这个属性值。

3 3 2 11。 一个大小(。 净只有)

size属性集的最大大小,以字节为单位,在列的数据。

3.3.3。 一个内联参数地图

如果你喜欢使用内联参数(参见3.0节和3.3.3),您可以添加额外的类型信息内联太。 inline参数映射语法允许您嵌入属性名、属性类型、列类型,变成一个参数化的SQL语句。 例20展示了示例18编码与内联参数。

ExampleA 20。 一个<声明>使用内联参数

<statement id=”insertProduct” parameterClass=”product”>  insert into PRODUCT (PRD_ID, PRD_DESCRIPTION)  values (#id#, #description#);</statement>

示例21演示如何声明类型内联。

ExampleA 21。 一个<声明>使用内联参数映射

<statement id=”insertProduct” parameterClass=”product”>  insert into PRODUCT (PRD_ID, PRD_DESCRIPTION)  values (#id:NUMERIC#, #description:VARCHAR#);</statement>

示例22显示了如何声明类型和null值替换。

ExampleA 22。 一个<声明>使用内联参数映射通过null值替换

<statement id=”insertProduct” parameterClass=”product”>  insert into PRODUCT (PRD_ID, PRD_DESCRIPTION)  values (#id:NUMERIC:-999999#, #description:VARCHAR:NO_ENTRY#);</statement>

注意

当使用内联参数,您不能指定null值替换,而还指定类型。 您必须指定两个由于解析顺序。

注意

“往返”透明度的null值,您还必须指定null值替换数据库列在你的结果图(见3.5节)。

注意

内联参数地图方便小工作,但是当有很多类型描述符和null值替换在一个复杂的语句,一个工业级、外部parameterMap可以解题。

3.3.4。 一个标准的类型参数

在实践中,你会发现许多语句把单个参数,通常一个整数或字符串。 而不是包装单一值在另一个对象,您可以使用标准库对象(字符串、整数,等等)作为参数直接。 示例23显示了一个使用标准声明类型参数。

ExampleA 23。 一个<声明>使用标准的类型参数

<!-- Java --><statement id=”insertProduct” parameter=”java.lang.Integer”>  select * from PRODUCT where PRD_ID = #value#</statement><!-- .NET --><statement id=”insertProduct” parameter=”System.Integer”>  select * from PRODUCT where PRD_ID = #value#</statement>

假设一个数字类型prd id是,当调用这个映射声明,一个标准的整数对象可以通过。 # #参数值将被替代为整数实例的值。 (这个名字的一个€œvaluea€只是一个占位符,您可以使用另一个名字,如果你喜欢。) 结果地图支持原始类型的结果。 为更多的信息关于使用原始类型作为参数,见3.4节,“结果地图”和“编程iBATIS数据映射”部分的开发人员指南为您的平台(部分4或5)。

为方便起见,原始类型别名的框架。 例如,一个€œinta€可以用来代替一个€œjava . lang。 Integera€或“系统整数”。 对于一个完整的列表,请参见第3.5节,一个€œ支持类型的参数和结果Mapsa€地图。

3 3 5。 一个地图或IDictionary类型参数

你也可以通过一个地图(Java)或IDictionary(. net)实例作为一个参数对象。 这通常是一个HashMap(Java)或一个散列表(对于。net)。 例24显示了一个<声明>使用地图或IDictionary为parameterClass。

ExampleA 24。 一个<声明>使用地图或IDictionary为parameterClass

<!-- Java --><statement id=”insertProduct” parameterClass=”java.util.Map”>  select * from PRODUCT  where PRD_CAT_ID = #catId#  and PRD_CODE = #code#</statement><!-- .NET --><statement id=”insertProduct” parameterClass=”System.Collections.IDictionary”>  select * from PRODUCT  where PRD_CAT_ID = #catId#  and PRD_CODE = #code#</statement>

在示例24,注意SQL在这个映射语句看起来像任何其他。 没有区别如何使用inline参数。 如果一个映射的实例被传递,地图必须包含键命名一个€œcatIda€和一个€œcodea€。 引用的值按那些键必须适当类型的列,就像他们将如果通过从一个属性对象。

结果地图支持地图和IDictionary类型作为结果太。 为更多的信息关于使用地图和IDictionary类型作为参数,见3.5节,“结果地图”和“编程iBATIS数据映射器”在你的平台的开发者指南(Section 5或6)。

为方便起见,地图和IDictionary类型别名的框架。 所以,一个€œmapa€可以用来代替一个€œjava实效。 Mapa€,”哈希表”可以用来代替“系统集合散列表”。 对于一个别名的完整列表,请参见第3.5节,一个€œ支持类型的参数和结果Mapsa€地图。

3.4。 结果地图

3.3节描述参数地图和内联参数,用于映射对象属性参数在数据库中查询。 结果地图完成这项工作通过映射一个数据库查询的结果(一组列)对象属性。 映射语句旁边,结果映射可能是其中最常用和最重要的特性来理解。

结果映射允许您控制如何提取数据从一个查询的结果,以及列映射到对象属性。 结果地图可以描述列类型,一个null值替换,和复杂的属性映射(包括集合)。 示例25显示了结构的< resultMap >元素。

ExampleA 25。 一个结构的< resultMap >元素。

<!-- Java --><resultMap id=”resultMapName” class=”someClassName” [extends=”parent-resultMap”]><result property=”propertyName” column=”COLUMN_NAME”  [columnIndex=”1”] [javaType=”int”] [jdbcType=”NUMERIC”]  [nullValue=”-9999”] [select=”someOtherStatement”]/>  <result ……/>  <result ……/>  <result ……/></resultMap><!-- .NET --><resultMap id=”parameterMapName” [class=”className”] [extends=”parent-resultMap”]>  <result property=”propertyName” column=”COLUMN_NAME”  [columnIndex=”1”] [dbType=”int”] [resultMapping="resultMapName"]  [nullValue=”-9999”] [select=”someOtherStatement”] [lazyLoad="true/false"]/>  <result ……/>  <result ……/></parameterMap>

在示例25,[方括号]显示可选属性。 这个ID属性是必需的,而且提供了一个名称为声明引用。 还需要class属性,并指定一个类型别名或者一个类的完全限定名。 这是这个类将被实例化和填充基于结果映射它包含。

这个resultMap可以包含任意数量的属性映射,映射对象属性的列的一个结果集,应用属性映射,列的顺序读取,它们定义的元素。 Mainting元素顺序确保一致的结果和提供者之间不同的驱动程序。

注意

与参数的类,其结果类必须是一个JavaBean或地图实例(iJava),或者一个属性对象或IDictionary实例(. net)。

3 4 1。 一个扩展resultMaps

可选的扩展属性可以设置为另一个resultMap的名字在基础这resultMap。 所有属性的“超级”将包括resultMap作为这个resultMap和值从“超级”resultMap设置在任何指定的值由这个resultMap。 其效果是类似于扩展类。

提示

“超级”resultMap必须在文件中定义之前resultMap的扩展。 这个类超级和子resultMaps不一定是相同的,并且不需要以任何方式有关。

3.4.2。 一个parameterMap属性

部分3 4 2 1通过3 4 2 7描述了< parameterMap >属性。

3 4 2 1。 一个属性元素

这个财产属性的结果映射属性是属性的名称(get方法)的结果对象,将返回映射的语句。 可以使用这个名字不止一次的次数取决于它是需要填充结果。

3 4 2 2一列

这个属性值的名称是在结果集中的列的值将被用来填充属性。

3 4 2 3 a columnIndex

作为一个可选的(最小)性能增强columnIndex属性值的索引列在ResultSet的值将被用来填充对象属性。 这是不太可能需要在99%的应用程序和牺牲可读性和可维护性为速度。 有些司机或提供者可能没有意识到任何性能好处,而其他的人则会急剧加速。

3 4 2 4。 一个jdbcType | dbType

这个jdbcType或dbType属性用于显式地指定数据库列类型的ResultSet列,将用于填充对象属性。 尽管结果地图没有同样的困难与null值,指定类型可以用于特定的映射类型如日期属性。 因为一个应用程序的语言有一个日期值类型和SQL数据库可能会有很多(通常至少3),指定日期可能成为必要在某些情况下,确保日期(或其它类型)的设置就是正确的。 同样,字符串类型可能被填充的VARCHAR或CLOB,所以CHAR指定类型可能需要在这些情况下太。

3 4 2 5。 一个将javaType(Java只有)

将javaType属性用于显式地指定Java属性类型的属性设置。通常这可以来自一个javabean属性通过反射,但某些映射如地图和XML映射不能提供类型的框架。 如果将javaType没有设置和框架无法确定输入类型是假定为对象。

3 4 2 6 a nullValue

这个nullValue属性可以设置为任何有效的值(基于属性类型)。 这个nullValue属性用来指定一个外向null值替换。 这意味着,当检测到的值是在对象属性,一个NULL将写入到数据库(相反的行为的一个入站NULL值替换)。 这允许您使用一个€œ很€null号码在您的应用程序的类型不支持null值(比如int,,)。 当这些类型的属性包含一个匹配的null值(比如,一个€“9999),一个null将被写入数据库而不是价值。

如果您的数据库有一个可以为空的列,但是你想让你的应用程序来表示空与一个常量值,您可以指定它在结果地图所示的示例26。

ExampleA 26。 一个指定nullvalue属性在一个结果图

<resultMap id=”get-product-result” class=”product”>         <result property=”id” column=”PRD_ID”/>        <result property=”description” column=”PRD_DESCRIPTION”/>        <result property=”subCode” column=”PRD_SUB_CODE”        nullValue=”-9999”/></resultMap>

在示例26,如果prd子代码是解读为NULL,那么子代码属性将设置为值-999。 这允许您使用一个原始类型在您的Java类来表示一个可以为空的列在数据库中。 记住,如果你想要这个工作的查询和更新/插入,您还必须指定nullValue在参数映射(本文前面讨论的)。

3 4 2 7一个选择

select属性用于描述一个对象之间的关系,并自动加载复杂(即用户定义的)属性类型。 声明属性的值必须是另一个声明的名称映射。 数据库列的值(列属性),是定义在相同的属性元素作为这个声明属性将被传递给相关的映射语句作为参数。 因此,列必须是一个支持,原始类型。 更多的信息关于支持原始类型和复杂的属性映射/关系是在本文档的后面讨论。

3 4 3。 一个隐含的结果地图

如果列一个SQL语句返回的匹配结果对象,你可能不需要一个明确的结果图。 如果你有控制的关系模式,您可以命名列,这样他们也作为属性名称。 在示例27,列名称和属性名称匹配,所以结果已经不需要地图。

ExampleA 27。 一个映射的声明这并不需要一个结果图

<statement id=”selectProduct” resultClass=”product”>  select  id,  description  from PRODUCT  where id = #value#</statement>

另一种跳过一个结果映射是使用列别名使列名称匹配属性名称,见例28。

ExampleA 28。 一个映射语句使用列alaising而不是一个结果图

<statement id=”selectProduct” resultClass=”product”>  select  PRD_ID as id,  PRD_DESCRIPTION as description  from PRODUCT  where PRD_ID = #value#</statement>

当然,这些技术将不会工作如果你需要指定一个列类型,一个null值,或任何其他财产属性。

大小写敏感性也可以是一个问题与隐式结果地图。 可以想象,你可以有一个对象与一个“FirstName”属性和一个“FirstName”属性。 当iBATIS试图匹配属性和列,heurstic是大小写敏感的,我们不能保证哪个属性将匹配。 (当然,很少有开发人员将有两个属性的名称,所以simiilar。)

最后一个问题是,有一些性能开销当iBATIS必须映射列和属性名称自动。 差异可以戏剧性如果使用第三方JDBC驱动程序支持ResultSetMetaData较差。

3.4.4的。 一个原始的结果(即。字符串、整数、Boolean)

很多时候,我们不需要返回一个对象具有多个属性。 我们只是需要一个字符串、整数、Boolean等等。 如果你不需要填充一个对象,iBATIS可以返回一个原始类型相反。 如果你只是需要值,您可以使用一个标准的类型结果类,见例29。

ExampleA 29。 一个选择一个标准的类型

<!-- Java --><select id=”selectProductCount” resultClass=”java.lang.Integer”>  select count(1)  from PRODUCT</select><!-- .NET --><select id=”selectProductCount” resultClass=”System.Int32”>  select count(1)  from PRODUCT</select>

如果需要,您可以参考标准类型使用一个标记牌,像一个€œvaluea€或€œ€期间,如例30。

ExampleA 30。 一个加载一个简单的列表的产品描述

<!-- Java --><resultMap id=”select-product-result” class=”java.lang.String”>  <result property=”value” column=”PRD_DESCRIPTION”/></resultMap><!-- .NET --><resultMap id=”select-product-result” class=”System.String”>  <result property=”value” column=”PRD_DESCRIPTION”/></resultMap>

3 4 5。 一个地图ResultMaps

而不是一个丰富的对象,有时你可能需要的是一个简单的键/值列表的数据,每个属性是一个条目的列表。 如果是这样,结果地图可以填充一个地图或IDictionary实例属性对象一样容易。 使用地图的语法或IDictionary富人是相同的对象语法。 31所示的示例中,只有结果对象的变化。

ExampleA 31。 结果地图可以使用通用的“输入型”对象

<!-- Java --><resultMap id=”select-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><!-- .NET --><resultMap id=”select-product-result” class=”HashTable”>  <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>

在示例31日HashMap的一个实例(或HashTable)将为每一行创建并填充在结果集中与产品数据。 属性名称属性,像ID,代码等等,将关键的条目,并映射的列的值将条目的值。

32所示示例,您还可以使用一个隐式的结果与一个IDictionary地图或映射类型。

ExampleA 32。 一个隐含的结果地图可以使用“输入型”对象太

<!-- Java --><statement id=”selectProductCount” resultClass=”java.util.HashMap”>  select * from PRODUCT</statement><!-- .NET --><statement id=”selectProductCount” resultClass=”HashTable”>  select * from PRODUCT</statement>

什么是返回的条目集示例xx取决于在结果集中的列。如果组列改变(因为列添加或删除),新组条目就会自动被返回。

3 4 6。 一个复杂的属性

在关系数据库中,一个表会经常引用另一个。 同样的,你的一些业务对象可能包括另一个对象或对象的列表。 类型,巢其他类型被称为“复杂的类型”。 你可能不希望一个语句返回一个简单的类型,但已经是一个十足的复杂类型。

在数据库中,一个相关的列通常是通过一个1:1关系代表,或一个1:M关系的类,它拥有复杂的属性从一个€œ许多sidea€的关系和属性本身就是从一个€œsidea€之一的关系。 从数据库返回的列不会是我们想要的财产;它是一个关键的用于另一个查询。

从框架的角度来看,问题与其说是加载一个复杂类型,但加载每个“复杂的财产”。 为了解决这个问题,您可以指定在结果映射一个语句运行加载给定的属性。 在示例33,“类别”属性的“选择产品结果”元素是一个复杂的属性。

ExampleA 33。 一个结果地图与一个复杂的属性

<resultMap id=”select-product-result” class=”product”>  <result property=”id” column=”PRD_ID”/>  <result property=”description” column=”PRD_DESCRIPTION”/>  <result property=”category” column=”PRD_CAT_ID” select=”selectCategory”/></resultMap><resultMap id=”select-category-result” class=”category”>  <result property=”id” column=”CAT_ID”/>  <result property=”description” column=”CAT_DESCRIPTION”/></resultMap><select id=”selectProduct” parameterClass=”int” resultMap=”select-product-result”>  select * from PRODUCT where PRD_ID = #value#</select><select id=”selectCategory” parameterClass=”int” resultMap=”select-category-result”>  select * from CATEGORY where CAT_ID = #value#</select>

在示例33,框架将会使用“selectCategory”语句填充“类别”属性。 每个类别的值被传递到“selectCategory”语句,返回的对象设置为分类属性。 当这个过程完成后,每个产品实例将有适当的类别对象实例设置。

3 4 7。 一个避免N + 1选择(1:1)

一个问题的例子可能是每当你33加载一个产品,两个语句执行:一个用于产品和一个用于类别。 一个产品的,这个问题似乎是微不足道的。 但如果你负载10产品,然后11语句执行。 100的产品,而不是一个语句产品声明执行,共有101语句执行。 执行的语句数例如33永远是N + 1:100 + 1 = 101。

缓解该问题的一个方法是缓存“selectCategory”语句。 我们可能会有一百个产品,但可能只有五类。 而不是运行一个SQL查询或存储过程,该框架将返回类别对象的缓存。 101年的声明仍将运行,但他们不会触及数据库。 (见3.7节了解更多的缓存)。

另一个解决方案是使用一个标准的SQL连接返回列你需要从另一个表。 一个连接可以把所有的列我们需要从数据库在一个单独的查询。 当你有一个嵌套对象,您可以引用嵌套的属性使用点符号,比如“类别描述”。

例34可以解决这些问题为例33,而是使用嵌套的属性使用一个加入相反。

ExampleA 34。 一个解决复杂的属性与一个连接

<resultMap id=”select-product-result” class=”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=”selectProduct” parameterClass=”int” resultMap=”select-product-result”>  select *  from PRODUCT, CATEGORY  where PRD_CAT_ID=CAT_ID  and PRD_ID = #value#</statement>

3 4 8。 一个复杂的集合属性

[TODO:修改从3 4 8结束的第三节)

也可以加载属性,代表列表的复杂对象。 在数据库中数据将被表示为一个M:M关系,或一个1:M关系,其中类包含一系列在一个€œ一sidea€和对象的关系在列表中在一个€œ许多sidea€。 加载对象的列表,那么就不需要更改语句(见上面的例子)。 唯一的区别需要导致iBATIS数据映射框架加载属性列表是业务对象上的属性必须类型java实效。 列表或java util集合。 例如,如果一个类别的一个列表的产品实例,映射看上去像这样(假设类别属性称为€œproductLista€类型的java util列表):

ExampleA 35。 一个映射,创建了一个复杂的对象的列表

<resultMap id=”select-category-result” class=”category”>  <result property=”id” column=”CAT_ID”/>  <result property=”description” column=”CAT_DESCRIPTION”/>  <result property=”productList” column=”CAT_ID” select=”selectProductsByCatId”/></resultMap><resultMap id=”select-product-result” class=”product”>  <result property=”id” column=”PRD_ID”/>  <result property=”description” column=”PRD_DESCRIPTION”/></resultMap><statement id=”selectCategory” parameterClass=”int” resultMap=”select-category-result”>  select * from CATEGORY where CAT_ID = #value#</statement><statement id=”selectProductsByCatId” parameterClass=”int” resultMap=”select-product-result”>  select * from PRODUCT where PRD_CAT_ID = #value#</statement>

3 4 9。 一个避免N + 1选择(1:M和M:N)

这类似于上面的1:1的情况,但更加令人担心的是,由于涉及的数据量可能很大。 上面的问题的解决方案是,每当你加载一个类别,两个SQL语句是实际运行(一个用于类别和一个用于列表相关的产品)。 这个问题似乎微不足道的装船时一个类别,但是如果你运行一个查询,加载十(10)类别,一个单独的查询将运行每个类别来加载相关产品的列表。 这导致11(11)查询总:一个用于分类列表,一个用于每个类别返回负载各相关产品的列表(N + 1或在这种情况下10 + 1 = 11)。 让这种情况更糟的是,我们€™re处理潜在的大的列表的数据。

1:N & M:N的解决方案? 目前,解决这个问题的功能没有实现,但发展的讨论是活跃的,我们期望它会包含在未来的发布。

3 4 10。 一个复合键或多个复杂的参数属性

您可能已经注意到,在上面的示例只有一个键被用作resultMap中指定的列属性。 这将表明,只有一列可以联系到一个相关的映射语句。 然而,有另一个语法,允许多个列传递给相关的映射语句。 这个方便的情况下一个复合键关系存在,或即使你只是想要使用一个参数的名称值# #。 替代语法的列属性只是{ param1 = column1,param2 = column2,一个€¦,paramN = columnN }。 考虑下面的例子,支付表由两个客户ID和订单ID:

ExampleA 36。 一个映射一个componsite键

<resultMap id=”select-order-result” class=”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=”selectOrderPayments”/></resultMap><statement id=”selectOrderPayments”  resultMap="select-payment-result”>  select * from PAYMENT  where PAY_ORD_ID = #itemId#  and PAY_CST_ID = #custId#</statement>

你也可以选择只指定列名称,只要它们€™再保险的顺序相同的参数。 例如:

{ORD_ID, ORD_CST_ID}

像往常一样,这是一个小小的性能增益与影响可读性和可维护性。

重要! 目前iBATIS数据映射框架并不会自动解决循环关系。 注意这个在实现父/子关系(树)。 一个简单方法是简单地定义第二个结果地图的情况下这并不加载父对象(反之亦然),或者使用一个join中描述了一个€œN + 1 avoidancea€解决方案。

注意! 一些JDBC驱动程序(例如。PointBase嵌入式)不支持多个结果集(每个连接)同时打开。 这种驱动程序不使用复杂对象的映射,因为SQL映射引擎需要多个结果集的连接。 再一次,使用一个join相反可以解决这个问题。

注意

结果映射的名字总是本地数据映射定义文件中定义。 你可以引用一个结果地图在另一个数据映射定义文件的前缀的名称和名称空间的结果映射SQL映射(在< sqlMap >设置根标记)。

注意

如果您使用的是Microsoft SQL Server 2000为JDBC驱动程序,您可能需要添加SelectMethod =光标来连接url以执行多个语句在手动事务模式(参见MS知识库文章313181:http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B313181)

3.5。 一个受支持的类型参数地图和结果地图

Java类型支持的数据映射框架,用于参数iBATIS部分所示3 5 1(Java)和部分3.5.2(. net)

表2显示了受支持的类型参数地图和结果地图对于Java。

为多2。 一个受支持的类型参数地图和结果地图(Java只有)

Java类型JavaBean /映射属性映射结果类/参数类* * *类型别名* *[:TODO:]   

*使用java . sql。 日期类型是气馁。 最佳实践是使用java实效。 日期相反。

* *。 类型别名可以用来代替完整的类名当指定参数或结果类。

* * *的原始类型(如int,布尔和浮动不能直接支持原始类型,因为iBATIS数据映射器是一个完全面向对象的方法。 因此所有的参数和结果必须是一个对象的最高水平。 顺便提一句,自动装箱功能的JDK 1.5将允许这些原语被使用。

表3显示了受支持的类型参数地图和结果地图为。net。

为多3。 一个受支持的类型参数地图和地图(结果。 净只有)

CLR类型对象/映射属性映射结果类/参数类* *类型别名* *系统arraylist是的是的列表系统布尔是的是的布尔,bool系统字节是的是的字节,字节系统char是的是的字符,字符系统datetime是的是的dateTime、日期系统十进制是的是的十进制、小数系统双是的是的双,双系统guid是的是的Guid系统hashtable是的是的地图、hashmap、散列表System.Int16是的是的Int16,短,短System.Int32是的是的Int32,int,int,整数,整数System.Int64是的是的Int64,很久很久System.SByte是的是的SByte,SByte系统单是的是的浮动,浮动,单身,单身系统字符串是的是的字符串,字符串系统时间间隔是的是的N / ASystem.UInt16是的是的短,短System.UInt32是的是的使用Uint,使用UintSystem.UInt64是的是的Ulong、Ulong

3.6。 一个受支持的数据库类型参数地图和结果地图

这个jdbcType / dbType属性支持的数据映射框架iBATIS参数显示在表4和表5。 表2显示了受支持的参数地图和地图jdbcTypefor结果为Java。 表3显示了受支持的参数DbTypes地图和结果地图为。net。

为多4。 一个受支持的jdbcTypefor参数地图和结果地图(Java只有)

[:TODO:]   [:TODO:]   

为多5。 一个受支持的DbTypes为参数地图和地图(结果。 净只有)

这个。 净框架数据提供者类型的一个参数对象的推断。 净框架类型的参数的值对象,或从DbType的参数对象。 下面的表显示了推断参数类型基于对象作为参数传递值或指定的DbType。 你可以指定类型的一个参数以通用的方式通过设置DbType属性的特定System.Data.DbType参数对象。CLR类型iBatis支持SqlDbTypeOleDbTypeOdbcTypeOracleTypeByte[]是的二进制、图像、VarBinary二进制,VarBinary二进制、图像、VarBinary布尔是的钻头布尔钻头字节字节——非常小的整数——非常小的整数字节DATETIME是的DateTime,SmallDateTime日期目前为止,DateTime,SmallDateTime、时间DATETIMEchar是的不支持charchar字节十进制是的十进制、金钱、SmallMoney十进制、货币、数字十进制,数字数量是的Guid是的uniqueidentifierGuiduniqueidentifierInt16是的SMALLINTSmallIIntSMALLINTInt16INT32是的int整数intINT32Int64是的BigIntBigIntBigInt数量是的真正真正字符串是的Char,Nchar NVarchar,、文本、VarCharChar、VarCharChar,NText NChar,,,文本,NVarChar VarCharnvarcharTimespan没有不支持DBTime时间DATETIMEuint16是的int————uint16uint32是的十进制————uint32UInt64是的十进制————数量

3.7。 一个缓存模型

一些值在数据库中都知道改变比其他人更慢。 为了提高性能,许多开发人员喜欢缓存常用数据,以避免不必要的出行做回数据库。 iBATIS提供自己的缓存系统,那你配置通过< cacheModel >元素。

从查询结果映射语句可以缓存仅仅通过指定在声明中cacheModel参数标记(见上图)。 缓存模式是一个配置的缓存,在您的数据映射定义配置文件。 缓存模型配置使用cacheModel元素如下:

ExampleA 37。 一个配制缓存使用缓存模型元素

<cacheModel id="product-cache" type ="LRU" readOnly=”true”>  <flushInterval hours="24"/>  <flushOnExecute statement="insertProduct"/>  <flushOnExecute statement="updateProduct"/>  <flushOnExecute statement="deleteProduct"/>  <property name=”cache-size” value=”1000” /></cacheModel>

缓存模型之上的一个实例将创建缓存命名一个€œproduct-cachea€使用最近最少使用(LRU)实现。 类型属性的值不是一个完全限定类名,或者一个别名为一个包含实现(见下文)。 基于冲洗元素内指定缓存模型,这种缓存刷新每24小时。 只可以有一个刷新间隔元素,它可以设置使用时,分,秒和毫秒。 此外,缓存刷新每当insertProduct,updateProduct或deleteProduct映射语句的执行。 可以有任意数量的一个€œexecutea潮红€元素指定一个缓存。 一些缓存实现可能需要额外的属性,比如一个€˜cache-sizea€™房地产上面演示。 对于LRU缓存的大小决定了数量的条目存储在缓存中。 一旦一个缓存模型配置,您可以指定要使用的缓存模式被映射的语句,例如:

ExampleA 38。 一个指定一个缓存模型从一个映射的声明

<statement id=”getProductList” cacheModel=”product-cache”>  select * from PRODUCT where PRD_CAT_ID = #value#</statement>

3.7.1。 一个只读和读/写(Java只有)

该框架既支持只读和读写缓存。 只读缓存是所有用户之间共享,因此提供了更大的性能优势。 然而,从一个只读缓存对象读不应该修改。 相反,一个新对象应该从数据库读取(或一个读/写缓存)更新。 另一方面,如果有一个意图使用对象检索和修改,一个读/写缓存是推荐(即要求)。 使用一个只读缓存,设置readOnly =一个€truea€在缓存模型元素。 使用一个读/写缓存,设置readOnly =一个€falsea€。 默认是只读的(真正的)。

3.7.2章。 一个缓存类型

缓存模型使用一个可插入框架支持不同类型的缓存。 实现类型属性中指定的cacheModel元素(如上面所讨论的)。 指定的类名必须是一个CacheController接口的实现,或四个别名在下面讨论。 进一步的配置参数可以传递到实现通过属性的元素包含在cacheModel的主体。 现在有4实现附带的分布。 这些如下:

3 7 3一个一个€œ€印象里

内存缓存实现使用引用类型来管理缓存行为。 这是,垃圾收集器有效地决定了位于缓存中或其他。 内存缓存是一个不错的选择,应用程序€™小姐没有一个可识别的对象重用模式,或应用程序在内存是稀缺(它会尽其所能)。

内存实现配置如下:

ExampleA 39。 一个配置一个内存类型的缓存

<cacheModel id="product-cache" type="MEMORY">   <flushInterval hours="24"/>  <flushOnExecute statement="insertProduct"/>  <flushOnExecute statement="updateProduct"/>  <flushOnExecute statement="deleteProduct"/>  <property name=”reference-type” value=”WEAK” /></cacheModel>

只有一个属性是公认的内存缓存实现。 这个属性命名,€˜reference-typea€™必须设置为一个值强、软或弱。 这些值对应于不同的内存引用类型的JVM中可用。

下面的表描述了不同的引用类型,可用于一个内存缓存。 为了更好的理解这个主题的引用类型,请参阅JDK文档以java . lang。 ref的更多信息œreachabilitya€一€。

为多6。 一个引用类型,可用于一个内存缓存

弱(默认)这个引用类型可能是最好的选择在大多数情况下,默认如果引用类型没有指定。 它将提高性能为流行的结果,但它绝对会释放内存用于分配其他对象,假设结果目前不使用。这个引用类型将减少的可能性耗尽内存如果结果不是目前在使用和内存需要其他对象。 然而,这并不是最激进的引用类型在这方面和记忆仍然可能分配,使之不可用更多的重要对象。强烈这个引用类型将保证结果保存在内存中,直到缓存是显式刷新(如按时间间隔或平在执行)。 这是理想的结果:1)非常小,2)绝对静态,3)经常使用。 其优势是,性能将会非常适合这个特定的查询。 缺点是,如果使用的内存这些结果是必要的,那么它将不会被释放,使房间其他对象(可能更重要的对象)。

3 7 4 a一个€œLRUa€

LRU缓存实现使用最近最少使用的算法来确定对象会自动从缓存中删除。 当该缓存将超过全部,至少最近访问对象将从缓存中删除。 这样,如果有一个特定的对象,通常被称为,它将停留在缓存中最可能被删除。 LRU缓存做一个好选择的应用程序模式使用特定对象可能是受欢迎的一个或多个用户在更长一段时间(比如翻页之间来回导航列表,流行的搜索键等等)。

LRU实现配置如下:

ExampleA 40。 一个配置一个LRU缓存类型

<cacheModel id="product-cache" type="LRU">  <flushInterval hours="24"/>  <flushOnExecute statement="insertProduct"/>  <flushOnExecute statement="updateProduct"/>  <flushOnExecute statement="deleteProduct"/>  <property name=”size” value=”1000” /></cacheModel>

只有一个属性是公认的LRU缓存实现。 这个属性命名,€˜sizea€™必须设置为一个整数值表示的对象的最大数量来保存在缓存中在一次。 一个重要的是要记住的是,一个对象可以是任何东西,从一个字符串ArrayList对象的实例。 所以小心不要存储在您的缓存和太多内存耗尽的风险!

3 7 5一个一个€œFIFOa€

FIFO缓存实现使用的一分之一先出算法来确定对象会自动从缓存中删除。 当缓存成为了完整的、最古老的对象将从缓存中删除。 FIFO缓存的有利于使用模式,一个特定的查询将被引用在接连几次,但后来可能不是一段时间后。

配置的FIFO实现如下:

ExampleA 41。 一个配置一个FIFO式缓存

<cacheModel id="product-cache" type="FIFO">  <flushInterval hours="24"/>  <flushOnExecute statement="insertProduct"/>  <flushOnExecute statement="updateProduct"/>  <flushOnExecute statement="deleteProduct"/>  <property name=”size” value=”1000” /></cacheModel>

只有一个属性是公认的FIFO缓存实现。 这个属性命名,€˜sizea€™必须设置为一个整数值表示的对象的最大数量来保存在缓存中在一次。 一个重要的是要记住的是,一个对象可以是任何东西,从一个字符串ArrayList对象的实例。 所以小心不要存储在您的缓存和太多内存耗尽的风险

注意

[Java只有]请参阅OSCache文档了解更多信息。 OSCache及其文档可以发现在以下开放交响乐的网站:http://www.opensymphony.com/oscache/

3.8。 一个动态SQL

一个非常常见的问题与直接使用JDBC是动态SQL。 它通常很难使用SQL语句,改变不仅的参数值,但哪些参数和列都包含在所有。 典型的解决方案通常是一个混乱的有条件的if - else语句和可怕的字符串串连操作。 期望的结果通常是一个实例查询,查询可以用来找到对象,类似于对象的示例。 iBATIS数据映射器API提供了一个相对优雅的解决方案,可以应用于任何映射声明元素。 这是一个简单的例子:

ExampleA 42。 一个简单的动态选择sttatement,有两种可能的结果

<select id="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>

在上面的例子中,有两个可能的语句,可以创建根据状态的一个€œida€属性参数bean。 如果id参数大于0,那么这个语句将被创建如下:

select * from ACCOUNT where ACC_ID = ?

或者如果id参数为0或更少,声明将如下所示。

select * from ACCOUNT

立即有用的,这可能不会成为一个更复杂的情况很明显直到遇到。 例如,下面是一个稍微复杂一点的例子。

ExampleA 43。 一个复杂的动态选择语句,16个可能的结果

<select 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</select>

根据具体情况,可能有多达16个不同的SQL查询生成从上面的动态语句。 代码的if - else结构和字符串串连操作会非常混乱,需要数百行代码。

使用动态语句很简单,插入一些条件式标签在动态的部分您的SQL。 例如:

ExampleA 44。 一个创建一个动态语句与条件式标签

<statement id="someName"  resultMap="account-result" >  select * from ACCOUNT  <dynamic prepend="where">  <isGreaterThan prepend="and" property="id" compareValue="0">    ACC_ID = #id#  </isGreaterThan>  <isNotNull prepend=”and" property="lastName">    ACC_LAST_NAME = #lastName#  </isNotNull>  </dynamic>  order by ACC_LAST_NAME</statement>

在上面的声明中,<动态>元素作为一个部分的SQL,是动态的。 动态元素是可选的,并且提供了一种方法来管理一个预谋预谋的情况下(例如,一个€œWHEREa€)不应该包括除非包含条件添加到该声明。 声明部分可以包含任意数量的条件元素(见下文),将决定一个所包含的SQL代码将被包含在语句。 所有的条件元素工作基于状态的参数对象传递到查询。 两个动态元素和条件元素有一个€œprependa€属性。 prepend属性是代码的一部分,是免费的,被覆盖的父母elementa€™年代预谋如果必要的话。 在上面的例子中,一个€œwherea€预谋将覆盖第一个真正的有条件的预谋。 这是必要的,以确保SQL语句是建立正确。 例如,对于第一个真正的条件,就不需要和,事实上它将打破语句。 以下部分描述的各种元素,包括二进制条件,一元的条件和迭代。

3 8 1。 一个二进制条件元素

二进制条件元素比较属性值到一个静态的淡水河谷或另一个属性值。 如果结果是真实的,身体的内容包括在SQL查询。

3 8 1 1。 一个二进制条件属性:
一个€“预谋的重写SQL部分,将前缀声明(可选)一个€“财产属性比较(必需)一个€compareProperty“比较的其他财产(必需或compareValue)一个€compareValue“值比较(或compareProperty所需

为多7。 一个二进制条件属性

< isEqual >检查平等的一个属性和一个值,或者另一个属性。< isNotEqual >检查不等式的一个属性和一个值,或者另一个属性。< isGreaterThan >检查是否一个属性是大于一个值或另一个属性。< isGreaterEqual >检查是否一个属性是大于或等于一个值或另一个属性。< isLessEqual >检查是否一个属性是小于或等于一个值或另一个属性。 示例用法:
<isLessEqual prepend=”AND” property=”age” compareValue=”18”>  ADOLESCENT = ‘TRUE’</isLessEqual>

3 8 2。 一元条件元素

一元运算条件元素检查的状态属性为一个特定的条件。

3 8 2 1。 一元条件属性:
一个€“预谋的重写SQL部分,将前缀声明(可选)财产一个€“要检查的特性(必需)

为多8。 一元条件属性

< isPropertyAvailable >检查是否一个属性是可用的(我。 e是一个属性参数bean)< isNotPropertyAvailable >检查是否一个属性不可用(我。 e不是房地产的参数bean)< isNull >检查是否一个属性是null。< isNotNull >检查是否一个属性不是null。< isEmpty >检查看看是否值的一个集合,字符串或字符串返回对象的值()属性是null或空(一个€œ一个€或大小()< 1)。< isNotEmpty >检查看看是否值的一个集合,字符串或字符串返回对象的值()属性不是null和非空(一个€œ一个€或大小()< 1)。例如用法:
<isNotEmpty prepend=”AND” property=”firstName” >  FIRST_NAME=#firstName# </isNotEmpty>
3 8 2 2。 一个参数礼物:

这些元素检查参数对象存在。

3 8 2 3。 一个参数呈现属性:

一个€“预谋的重写SQL部分,将前缀声明(可选)

为多9。 一个测试来看看一个参数是礼物

< isParameterPresent >检查是否存在的参数对象(而不是null)。< isNotParameterPresent >检查看看是否参数对象不存在(空)。 示例用法:
<isNotParameterPresent prepend=”AND”>  EMPLOYEE_TYPE = ‘DEFAULT’</isNotParameterPresent>
3 8 2 4一个迭代:

该标签将遍历一个集合和重复身体内容对于每个列表中的一个项目

3 8 2 5。 一个迭代属性:
一个€“预谋的重写SQL部分,将前缀声明(可选)一个€“财产的一个属性类型的java实效。 列表,迭代(必需)打开一个€“字符串来打开整个块迭代,用于方括号(可选)关闭一个€“字符串来关闭整个块迭代,用于方括号(可选)结合一个€“字符串被应用于每个迭代之间,用于和和或(可选)

为多10。 一个创建一个列表的有条件的条款

< iterate >遍历一个属性的类型是java实效。 列表示例用法:
<iterate prepend=”AND” property=”userNameList”  open=”(” close=”)” conjunction=”OR”>  username=#userNameList[]#</iterate>
注意:这是非常重要的,包括在方括号[]在列表的末尾属性名当使用迭代元素。 这些方括号区分这个对象作为一个列表来让解析器从简单的输出作为字符串列表。

3 8 3。 一个简单的动态SQL元素

尽管力量的全动态映射声明API上面所讨论的,有时候你只需要一个简单的、小块SQL是动态的。 为此,SQL语句和语句可以包含简单的动态SQL元素来帮助实现动态order by子句中,动态选择列或几乎任何SQL语句的一部分。 这个概念很像内联参数地图,但使用一种稍有不同的语法。 考虑下面的例子:

ExampleA 45。 一个动态元素排序顺序的变化

<statement id=”getProduct” resultMap=”get-product-result”>  select * from PRODUCT order by $preferredOrder$</statement>

在上面的例子中,preferredOrder动态元素将被替换为preferredOrder属性的值的参数对象(就像一个参数地图)。 不同的是,这是一个基本的改变SQL语句本身,这是更严重的比简单地设置一个参数值。 一个错误使在动态SQL元素可以介绍安全性、性能和稳定性的风险。 小心做大量的冗余的检查,以确保简单的动态SQL元素被适当地使用。 同时,留心你的设计,因为有可能侵犯了你的数据库细节的业务对象模型。 例如,您可能不希望一个列名称用于一个order by子句来结束了作为一个属性在您的业务对象,或作为一个字段值在你的服务器页面。

简单的动态元素可以包含在<报表>和派上用场时需要修改SQL语句本身。 例如:

ExampleA 46。 一个动态元素,改变了比较运算符

<statement id=”getProduct” resultMap=”get-product-result”>  SELECT * FROM PRODUCT  <dynamic prepend=”WHERE”>    <isNotEmpty property=”description”>      PRD_DESCRIPTION $operator$ #description#    </isNotEmpty>  </dynamic></statement>

在上面的例子中,操作符属性的参数对象将用于替换操作符$令牌美元。 因此,如果操作符属性等于一个€˜一样€™和description属性等于一个€˜%的狗%一个€™,然后生成的SQL语句将:

  SELECT * FROM PRODUCT WHERE PRD_DESCRIPTION LIKE ‘%dog%’

4。 Java开发人员指南

4.1。 一个安装iBATIS数据映射为Java

安装iBATIS数据映射框架是一个简单的事将适当的JAR文件在classpath。 这可以是指定的类路径在JVM启动时间(java参数),或者它可能是/ - inf / lib目录的一个web应用程序。 一个Java类路径的完整讨论超出了本文的范围。 如果你€™再保险新的Java和/或类路径,请参阅下面的参考资料:

http://java.sun.com/j2se/1.4/docs/tooldocs/win32/classpath.html http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html http://java.sun.com/j2se/1.4.2/docs/

iBATIS数据映射器带有以下JAR文件应该在类路径:

为多11。 一个JAR文件使用iBATIS数据映射

文件名描述需要ibatis常见的jariBATIS常见的公用事业是的ibatis-sqlmap.jariBATIS数据映射框架是的ibatis dao 1××b jar遗留iBATIS数据访问对象的向后兼容性。没有ibatis兼容遗留iBATIS Java API的向后兼容性。没有

以下4.4.1。 一个JAR文件和依赖关系

当一个框架有太多的依赖项,就很难融入一个应用程序和与其他框架。 一个关键的焦点2.0是依赖关系管理和还原。 因此,如果你运行JDK 1.4,那么唯一的真正的依赖是Jakarta Commons日志框架。 可选的JAR文件的库被组织成包结构中发现的/ lib /可选目录的分布。 它们被划分的函数。 以下是总结当你需要使用可选的软件包。

为多12。 一个何时使用可选的软件包

描述当使用目录遗留JDK支持如果你运行不到JDK 1.4,如果你的应用程序服务器也不已经供应这些jar,那么你将需要这些可选包。/ lib /可选/ jdbc / lib /可选/ jta / lib /可选/ xml遗留DAO支持如果你€™重新使用旧iBATIS(1. x)DAO框架,您可以继续这样做仅仅通过包括现有的DAO JAR。 一个是包含在框架在这个可选包。/ lib /可选/老刀运行时字节码增强如果你想使CGLIB 2.0字节码增强改进延迟加载和反射性能。/ lib /可选/增强DataSource的实现如果你想使用雅加达DBCP连接池。/ lib /可选/ dbcp分布式缓存如果你想使用OSCache集中或分布式缓存支持。/ lib /可选/缓存日志解决方案如果你想使用Log4J日志记录。/ lib /可选/日志记录

4 1 2。 一个由升级版本1。 x版本2. x

4 1 2 1。 一个你应该升级吗?

最好的方法来确定你应该升级是尝试它。 有一些升级路径。

  1. 版本2.0保持了几乎完全向后兼容的1。 x版本,因此对某些人仅仅替换JAR文件可能是足够的。 这个方法产生最少的好处,但也是最简单的。 你夫人€™t需要改变您的XML文件或您的Java代码。 一些不兼容问题可能会发现虽然。

  2. 第二个选择是将XML文件到2.0规范,但继续使用1。 x的Java API。 这是一个安全的解决方案,更少的兼容性问题会发生在映射文件(有一些)。 一个Ant任务包含在框架来转换XML文件(在下面描述)。

  3. 第三种选择是把你的XML文件(如# 2)和您的Java代码。 没有工具转换为Java代码,因此它必须手动完成。

  4. 最后的选择是不升级在所有。 如果你有困难,小姐€™t害怕离开你的工作系统1。 x版本。 Ita€™年代可能不是一个坏主意离开你的旧应用程序1。 x和开始新的应用程序只有2.0。 当然,如果一个旧的应用程序被严重重构超越的角度识别无论如何,你不妨升级iBATIS数据映射器太。

4 1 2 2。 一个转换的XML配置文件从1。 x 2. x

2.0框架包含一个XML文档转换器运行通过Ant构建系统。 转换您的XML文档是完全可选为1。 x的代码会自动改变旧的XML文件在飞。 不过,ita€™是个好主意€转换您的文件一旦有™再保险舒适的想法升级。 你将会经历更少的兼容性问题和百度€™就能够利用一些新特性(即使有€™再保险仍使用1。 x的Java API)。

Ant任务看起来像这个在您的构建。 xml文件:

ExampleA 47。 一个Ant TaskDef

<target>  <taskdef name="convertSqlMaps"    classname="com.ibatis.db.sqlmap.upgrade.ConvertTask"    classpathref="classpath"/> <target name="convert">  <convertSqlMaps todir="D:/targetDirectory/" overwrite="true">    <fileset dir="D/sourceDirectory/"> <include      name="**/maps/*.xml"/>     </fileset>   </convertSqlMaps></target>

正如您可以看到的,它的工作原理就像蚂蚁复制任务,而且事实上它扩展Ant任务副本,所以你可以真正做什么完成这个任务,复制可以做(参见蚂蚁复制任务文档了解详细信息)。

4 1 2 3。 一个JAR文件:与旧的,在与新

当升级,这是一个好主意,删除所有现有的(旧)iBATIS SQL映射文件和依赖项,换上新的文件。 一定不要删除任何其他组件或框架,你可能仍然需要。 注意,大多数的JAR文件是可选的依赖于你的环境。 请参阅上面的讨论更多的信息关于JAR文件和依赖关系

下面的表总结了旧的文件和新的。

为多13。 一个旧文件与新文件

旧文件新文件

ibatis-db.jar After    release 1.2.9b, this file was split into the following 3 files:    batis-common.jar ibatis-dao.jar    ibatis-sqlmap.jar

ibatis-common.jar (required)    ibatis-sqlmap.jar (required) ibatis-dao-1-2-9-b.jar (optional 1.x DAO)    ibatis-compat (optional 1.x compatibility)

commons-logging.jar    commons-logging-api.jar commons-collections.jar commons-dbcp.jar    commons-pool.jar oscache.jar jta.jar dbc2_0-stdext.jar xercesImpl.jar    xmlParserAPIs.jar jjdom.jar
commons-logging-1-0-3.jar (required)    commons-collections-2-1.jar (optional) commons-dbcp-1-1.jar (optional)    commons-pool-1-1.jar (optional) oscache-2-0-1.jar (optional)    jta-1-0-1a.jar (optional) jdbc2_0-stdext.jar (optional)    xercesImpl-2-4-0.jar (optional) xmlParserAPIs-2-4-0.jar (optional)    xalan-2-5-2.jar (optional) log4j-1.2.8.jar (optional)    cglib-full-2-0-rc2.jar (optional)

4.2。 一个配置数据映射为Java

iBATIS数据映射器配置使用一个中央XML描述符,它提供了详细的为你的数据源、数据地图,和其他的一些功能,比如缓存,事务和线程管理。 在运行时,您的应用程序代码调用一个iBATIS库例程读取和解析主要配置文件。 其他XML描述符可以被引用,但是每个数据映射器客户端实例“靴”从一个配置文件。

4 2 1。 一个数据映射器客户

每个数据映射器客户机(实例的SqlMapClient)是由阅读一个配置文件。 每个配置文件只能指定一个数据库或数据源。 然而,你可以使用多个数据映射器客户在您的应用程序。 只是创建另一个配置文件,该文件的名称传递数据映射器客户机创建的。 配置文件可能使用一个不同的帐户与相同的数据库,或者引用不同的数据库在不同的服务器上。 你甚至可以读和写从一个客户到另一个,如果这就是你需要做的。

4.2.2。 一个数据映射器配置文件(SqlMapConfig.xml)

一个示例配置文件显示在下面的例子:

ExampleA SqlMapConfig 48.。 xml对于Java

<?xml version="1.0" encoding="utf-8"?><!DOCTYPE sqlMapConfig   PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"   "http://www.ibatis.com/dtd/sql-map-config-2.dtd"><sqlMapConfig>  <properties resource="properties/database.properties"/>  <settings    cacheModelsEnabled="true"    enhancementEnabled="true"    maxSessions="64"    maxTransactions="8"    maxRequests="128"/>  <transactionManager type="JDBC">    <dataSource type="SIMPLE">      <property value="${driver}" name="JDBC.Driver"/>      <property value="${url}" name="JDBC.ConnectionURL"/>      <property value="${username}" name="JDBC.Username"/>      <property value="${password}" name="JDBC.Password"/>      <property value="15" name="Pool.MaximumActiveConnections"/>      <property value="15" name="Pool.MaximumIdleConnections"/>      <property value="1000" name="Pool.MaximumWait"/>    </dataSource>  </transactionManager>  <sqlMap resource="com/ibatis/jpetstore/persistence/sqlmapdao/sql/Account.xml"/>  <sqlMap resource="com/ibatis/jpetstore/persistence/sqlmapdao/sql/Category.xml"/>  <sqlMap resource="com/ibatis/jpetstore/persistence/sqlmapdao/sql/Product.xml"/>  <sqlMap resource="com/ibatis/jpetstore/persistence/sqlmapdao/sql/Sequence.xml"/>  <sqlMap resource="com/ibatis/jpetstore/persistence/sqlmapdao/sql/LineItem.xml"/>  <sqlMap resource="com/ibatis/jpetstore/persistence/sqlmapdao/sql/Order.xml"/>  <sqlMap resource="com/ibatis/jpetstore/persistence/sqlmapdao/sql/Item.xml"/></sqlMapConfig>

第4.2.3。 一个数据映射器的配置元素

接下来的几个小节描述的元素数据映射为Java配置文档。

4 2 3 1。 一个<属性>元素

有时我们使用的值在一个XML配置文件出现在不止一个元素。 通常,有价值,当我们移动应用程序的更改从一个服务器到另一个。 帮助你管理的配置值,您可以指定一个标准的属性文件(名称=值)的一部分,一个数据映射器配置。 每一个名为value的属性文件变成了一个“壳”变量,可应用于整个数据映射器配置,包括数据映射定义文件(参见第三节)。例如,如果属性文件包含

username=iBATIS

然后任何元素的数据映射器配置,包括数据映射,可以使用变量$ { username }插入值“iBATIS”。 例如:

<dataSource connectionString="user id=${username}; 

属性是方便的在构建、测试和部署。 性能使它容易重新配置您的应用程序的多个环境或使用的自动化工具的配置(如。Ant)。

属性可以从类路径装入(使用资源属性)或从任何有效的URL(使用URL属性)。 例如,一个固定的路径加载文件,使用:

<properties url=”file:///c:/config/my.properties” />
1 1 2 3 4。 一个<属性>属性

只可以有一个<属性>元素,它可以接受两个属性:资源和url。

资源——一个属性文件在类路径的某处找到。url——一个属性上发现的本地文件系统或其他统一的位置。
4 2 3 2。 一个<设置>元素

有许多极限,最大值,和其他设置框架使用了。 设置适合一个应用程序可能不适合另一个。 <设置>元素允许您配置这些选项和优化的SqlMapClient实例创建的XML文档。 所有的设置有违约,你可以省略的设置元素或它的任何属性。 设置属性和它们的行为他们控制如表9。

为多14。 一个属性的设置元素

cacheModelsEnabled

这个设置全局启用或禁用所有缓存模型为一个SqlMapClient。 这对调试可以派上用场。

Example: cacheModelsEnabled=”true”Default: true (enabled)

useStatementNamespaces(Java)

与启用该设置,您必须总是把映射声明他们的完全限定名称,它是结合sqlMap的名字和声明的名字。 例如:

queryForObject(“sqlMapName.statementName”);(See the Developers Guide for your platform (Section 4 or 5) for more about creating Data Map clients.)Example: useStatementNamespaces=”false”Default: false (disabled)
maxRequests

这是线程的最大数量,可以执行一条SQL语句在一个时间。 线程超出了集值将被阻塞,直到另一个线程执行完成。 不同的DBMS有不同的限制,但没有数据库是没有这些限制。 这通常应该至少10倍maxTransactions(见下文),总是应该大于两maxSessions和maxTransactions。 经常减少并发请求的最大数量可以增加性能。

Example: maxRequests=”256”Default: 512
maxSessions

这是会话数量(或客户),可以活跃在给定的时间。 一个会话要么是一个显式的会话、请求的编程,或者它是自动每当一个线程利用一个SqlMapClient实例(如执行一个语句等等)。 这总是应该大于或等于maxTransactions和不到maxRequests。 减少最大并发会话的数量可以减少总的内存足迹。

Example: maxSessions=”64”Default: 128
maxTransactions

这是线程的最大数量,可以输入SqlMapClient.startTransaction()。 线程超出了集值将被阻塞,直到另一个线程退出。 不同的DBMS有不同的限制,但没有数据库是没有这些限制。 这个值应该总是小于或等于maxSessions和总是远低于maxRequests。 通常降低了最大数量的并发来自事务可以提高性能。

Example: maxTransactions=”16”Default: 32
lazyLoadingEnabled

这个设置全局启用或禁用所有的SqlMapClient延迟加载。 这对调试可以派上用场。

Example: lazyLoadingEnabled=”true”Default: true (enabled)
enhancementEnabled

此设置允许运行时字节码增强促进优化的JavaBean属性访问以及增强的延迟加载。

Example: enhancementEnabled=”true”Default: false (disabled)
errorTracingEnabledTODO:
4 2 3 3。 一个< typeAlias >元素

这个typeAlias元素允许您指定一个简短的名字代替完全限定类名。 例如:

<typeAlias name="Account" assembly="NPetshop.Domain.dll" class="NPetshop.Domain.Accounts.Account" />

然后您可以参阅“帐户”或“账户”在你经常不得不拼出的完全限定类名。

3 1 2 3 4。 一个< typeAlias >属性

< typeAlias >元素有两个必需的属性:

别名——一个惟一的标识符对于这个别名——完全限定类名,包括包参考
4 2 3 3 2。 一个预定义的类型别名

有一些预定义的别名为Java,它们是:

为多15。 事务管理器别名(Java)

JDBC = com.ibatis.sqlmap.engine.transaction.jdbc.JdbcTransactionConfig JTA = com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig EXTERNALcom.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig

为多16。 一个数据源工厂别名(Java)

SIMPLE = com.ibatis.sqlmap.engine.datasource.SimpleDataSourceFactory DBCP = com.ibatis.sqlmap.engine.datasource.DbcpDataSourceFactory JNDI = com.ibatis.sqlmap.engine.datasource.JndiDataSourceFactory

4 2 3 4。 一个< transactionManager >元素

这个。 净实现只支持ado控制事务。

4 2 3 4 1。 一个< dataSource >元素(在transactionManger)

Datasource元素可以指定数据源的实现。 DataSourceFactory捆绑的实现是在下一节讨论。

4 2 3 5。 一个数据源工厂

三个数据源工厂提供Java实现,您也可以编写自己的。 DataSourceFactory实现的绑定部分中,讨论了4 5 1 2 3通过部分4 2 3 5 3。

1 2 3 4 5 SimpleDataSourceFactory

SimpleDataSource的工厂提供了一个基本的实现一个池数据源,是理想的提供连接的情况下没有容器提供的数据源。 它是基于iBATIS SimpleDataSource连接池实现。

ExampleA 49。 一个SimpleDataSourceFactory TransactionManager元素(Java)

<transactionManager type="JDBC">            <dataSource type="SIMPLE"> <property name="JDBC.Driver"            value="org.postgresql.Driver"/> <property            name="JDBC.ConnectionURL"            value="jdbc:postgresql://server:5432/dbname"/> <property            name="JDBC.Username" value="user"/> <property            name="JDBC.Password" value="password"/> <!-- OPTIONAL            PROPERTIES BELOW --> <property            name="Pool.MaximumActiveConnections" value="10"/> <property            name="Pool.MaximumIdleConnections" value="5"/> <property            name="Pool.MaximumCheckoutTime" value="120000"/> <property            name="Pool.TimeToWait" value="10000"/> <property            name="Pool.PingQuery" value="select * from dual"/> <property            name="Pool.PingEnabled" value="false"/> <property            name="Pool.PingConnectionsOlderThan" value="0"/> <property            name="Pool.PingConnectionsNotUsedFor" value="0"/>            </dataSource> </transactionManager>
4 2 3 5 2一个DbcpDataSourceFactory

这个实现使用雅加达DBCP(数据库连接池)提供连接池服务通过数据源API。 此数据源是理想的应用程序/ web容器不能提供一个数据源的实现,或有€™重新运行一个独立的应用程序。 一个示例的配置参数,必须被指定为DbcpDataSourceFactory如下:

ExampleA 50。 一个DbcpDataSourceFactory TransactionManager元素(Java)

<transactionManager            type="JDBC"> <dataSource type="DBCP"> <property            name="JDBC.Driver" value="${driver}"/> <property            name="JDBC.ConnectionURL" value="${url}"/> <property            name="JDBC.Username" value="${username}"/> <property            name="JDBC.Password" value="${password}"/> <!-- OPTIONAL            PROPERTIES BELOW --> <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 * from ACCOUNT"/> <property            name="Pool.LogAbandoned" value="false"/> <property            name="Pool.RemoveAbandoned" value="false"/> <property            name="Pool.RemoveAbandonedTimeout" value="50000"/>            </datasource>            </transactionManager>
4 2 3 5 3 a JndiDataSourceFactory

该实现将检索一个数据源的实现从一个JNDI上下文从在一个应用程序容器。 这通常用在当应用服务器在使用和容器管理的连接池和相关的DataSource的实现都提供了。 标准的方法来访问JDBC DataSource的实现是通过一个JNDI上下文。 JndiDataSourceFactory提供的功能来访问这样一个数据源通过JNDI。 配置参数,必须指定在datasource节如下:

ExampleA 51。 一个JndiDataSourceFactory TransactionManager元素(Java)

<transactionManager            type="JDBC" > <dataSource type="JNDI"> <property            name="DataSource" value="java:comp/env/jdbc/jpetstore"/>            </dataSource> </transactionManager>

上面的配置将使用普通JDBC事务管理。 但与容器管理的资源,您可能还想将它配置为全局事务如下:

ExampleA 52。 一个TransactionManager元素配置为全球事务(Java)

<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>

注意,属性指向UserTransaction JNDI位置UserTransaction实例可以被发现。 这就需要JTA事务管理,这样你的数据地图可以参加一个更广泛的范围事务涉及其他数据库和事务性资源。

4 2 3 6。 一个< sqlMap >元素

每天,你的大部分工作将与数据地图。 数据映射定义实际的SQL语句或存储过程使用的应用程序。 参数和结果对象也定义为数据地图的一部分。 随着应用程序的增长,你可能会有几个种类的数据地图。 帮助你保持你的数据地图有组织的,您可以创建任意数量的数据映射定义文件并将它们通过引用到数据映射器配置。 所有的定义文件使用一个数据映射器实例必须在配置文件中列出。

例32显示< sqlMap >元素加载一组数据映射定义,要么从类路径或一个URL。

ExampleA 53。 一个数据图元素

<!-- CLASSPATH RESOURCES (Java) --><sqlMap resource="com/ibatis/jpetstore/persistence/sqlmapdao/sql/Category.xml"/><sqlMap resource="com/ibatis/jpetstore/persistence/sqlmapdao/sql/Product.xml"/><!-- URL RESOURCES (Java)(absolute) --><sqlMap url="file:///c:/config/Category.xml" /><sqlMap url="file:///c:/config/Product.xml" /><!-- Application path (.NET) --><sqlMap resource="sql/Category.xml"/><sqlMap resource="://sql/Product.xml"/><!-- URL RESOURCES (.NET)(absolute) --><sqlMap url="c:/config/maps/Category.xml"/><sqlMap url="c:/config/Maps/Product.xml"/>

第三节描述了数据映射定义文件。

4.3。 一个编程和iBATIS数据映射器:Java API

SqlMap的客户端API是简单的和最小。 它提供了程序员与能力做四个主要功能:配置数据地图,执行一个SQL更新(包括插入和删除),执行一个查询一个对象,并执行一个查询对象的一个列表。

4 3 1一个配置

配置iBATIS数据映射器是微不足道的,一旦创建了您的数据映射定义文件和数据映射器配置文件(上面所讨论的)。 SqlMapClient实例使用SqlMapClientBuilder建造。 这类有一个基本的静态方法命名buildSqlMap()。 buildSqlMap()方法的简单实例,带领读者可以阅读在sqlMap-config的内容。 xml(不一定是命名)。

String resource = “com/ibatis/example/sqlMap-config.xml”;Reader reader = Resources.getResourceAsReader (resource);SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMap(reader);

4 3 2一个事务

默认情况下,调用任何executeXxxx()方法在一个SqlMapClient实例将自动提交/回滚。 这意味着每次调用executeXxxx()将一个单一的工作单元。 这是简单的,但事实上不是理想的如果你有大量的语句,必须执行作为一个单一的工作单元(即要么成功或失败作为一个群体)。 这就是事务发挥作用。

如果你€™再保险使用全局事务(配置数据映射器配置文件),您可以使用自动提交,仍然能够工作单元的行为。 然而,它仍然可能是理想的性能原因划分事务边界,因为它减少了交通连接池和数据库连接的初始化。

这个SqlMapClient接口的方法,允许您划分事务界限。 一个事务可以启动、提交和/或回滚使用以下方法SqlMapClient界面:

public void startTransaction () throws SQLExceptionpublic void commitTransaction () throws SQLExceptionpublic void endTransaction () throws SQLException

通过开始一个事务你检索连接池连接的,开放它接收SQL查询和更新。

使用事务的一个示例如下:

ExampleA 54。 一个使用事务

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 ();  }}

注意endTransaction()被称为不管一个错误。 这是一个重要的步骤,确保清理。 规则是:如果你叫startTransaction()是绝对肯定叫endTransaction()(你是否提交或没有)。

注意

事务不能嵌套。 调用.startTransaction()从同一线程不止一次,在调用commit()和rollback(),将会导致抛出一个异常。 换句话说,每个线程可以有——大多数-一个事务中打开,每SqlMapClient实例。

注意

SqlMapClient事务使用Javaa€™年代ThreadLocal存储来存储事务对象。 这意味着每个线程调用startTransaction()将获得一个独特的连接对象为他们的事务。 唯一的方法返回一个连接到数据源(或关闭连接)是调用commitTransaction()或endTransaction()。 不这样做可能会导致您的池耗尽连接和锁定。

4 3 2 1。 一个自动交易

尽管使用显式的交易非常强烈推荐,有一个简化的语义,可以用于简单的需求(通常只读)。 如果你没有明确限定交易使用startTransaction(),commitTransaction()和endTransaction()方法,它们将被称为自动为你当你执行一个语句块之外的事务中演示了上面的。 例如:

ExampleA 55。 一个设置一个自动交易

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 {    Item item = (Item) sqlMap.queryForObject ("getItem", itemId);    item.setDescription (“TX1”);    // No transaction demarcated, so transaction will be automatic (implied)    sqlMap.update ("updateItem", item);    item.setDescription (newDescription);    item.setDescription (“TX2”);    // No transaction demarcated, so transaction will be automatic (implied)    sqlMap.update("updateItem", item);  }   catch (SQLException e) {    throw (SQLException) e.fillInStackTrace();  }}

注意

非常小心使用自动交易,尽管他们可以有吸引力,你会遇到麻烦,如果你的工作单元需要超过一个更新到数据库。 在上面的示例中,如果第二个调用一个€œupdateItema€失败,项目描述仍将更新为第一个新的描述一个€œTX1a€(即这不是事务性行为)。

4.3.3。 一个全球(分布式)事务

iBATIS数据映射框架也支持全局事务。 全局事务也被称为分布式事务,将允许您更新多个数据库(或其他JTA兼容的参考资料)在同一个工作单元(即更新多个数据源可以成功或失败作为一个群体)。

4 3 3 1。 一个外部/程序化的全局事务

你可以选择来管理全球事务外,通过编程方式(手工编码),或通过实现另一个框架如非常常见的EJB。 使用EJB可以声明性地限定(设置界限的)一个事务在EJB部署描述符。 进一步讨论如何这样做的超出了本文的范围。 启用支持外部或编程全局事务,您必须设置< transactionManager > type属性到一个€œEXTERNALa€在您的数据映射器配置文件(见上图)。 当使用外部控制全局事务,SQL映射事务控制方法都有些多余,因为开始、提交和回滚的事务将由外部事务管理器。 但是,可能有一个性能好处还是你的交易使用SqlMapClient标定方法startTransaction(),commitTransaction()和endTransaction()(与允许自动事务启动和提交或回滚)。 通过继续使用这些方法,您将保持一致的编程范式,以及你将能够减少连接请求的数量从连接池中。 进一步的好处是,在某些情况下,您可能需要更改资源的顺序关闭(commitTransaction()或endTransaction())与全球事务被提交。 不同的应用程序服务器和事务管理器有不同的规则(不幸的是)。 除了这些简单的考虑,有必要进行任何修改你的数据映射代码使用全局事务。

4 3 3 2。 一个管理全球事务

iBATIS数据映射框架也可以为您管理全球事务。 启用支持管理全球事务,您必须设置< transactionManager > type属性到一个€œJTAa€在您的SQL映射配置文件并设置一个€œUserTransactiona€财产完整的JNDI名称的SqlMapClient实例将找到UserTransaction实例。 看到< transactionManager >讨论以上全部配置细节。

编程的全局事务并没有太大的不同,但是有一些小型的考虑。 这里有一个例子:

try {  orderSqlMap.startTransaction();  storeSqlMap.startTransaction();  orderSqlMap.insertOrder(…);  orderSqlMap.updateQuantity(…);  storeSqlMap.commitTransaction();  orderSqlMap.commitTransaction();  }   finally {    try {      storeSqlMap.endTransaction()    }     finally {      orderSqlMap.endTransaction()    }}

在这个例子中,有两个SqlMapClient实例,我们将假定使用的是两个不同的数据库。 第一SqlMapClient(orderSqlMap),我们使用开始一个事务也将启动全局事务。 在那之后,所有其他活动被认为是全局事务的一部分,直到同样的SqlMapClient(orderSqlMap)调用commitTransaction()和endTransaction(),此时全球事务被提交和所有其他的工作被认为是做的。

警告

虽然这似乎很简单,这是非常重要的,你€小姐™t过度使用全局(分布式)事务。 性能有一定影响,以及额外的复杂的配置要求,您的应用程序服务器和数据库驱动程序。 虽然它看起来容易,你可能仍然经历一些困难。 记住,ejb有更多的行业的支持和工具来帮助你,和你一起仍然可能会更好使用会话ejb的任何工作,需要分布式事务。 这个示例应用程序在www.ibatis.com找到JPetStore是一个示例使用数据映射器全局事务。

4.3.4。 一个批次(Java只有)

如果你有大量的非查询(插入/更新/删除)语句来执行,您可能想执行它们作为一个批处理来减少网络流量,并允许JDBC驱动程序来执行额外的优化(例如压缩)。 使用简单的批次是iBATIS数据映射器API,两个简单的方法让你划清界限的批处理:

sqlMap.startBatch();//…execute statements in betweensqlMap.executeBatch();

在调用executeBatch(),所有成批的语句将执行通过JDBC驱动程序。

4 3 5。 一个执行语句通过SqlMapClient API

SqlMapClient提供一个API来执行所有映射语句关联到它。 这些方法如下:

ExampleA 56。 一个iBATIS数据映射器客户机API

public int insert(String statementName, Object parameterObject)throws SQLExceptionpublic int update(String statementName, Object parameterObject)throws SQLExceptionpublic int delete(String statementName, Object parameterObject)throws SQLExceptionpublic Object queryForObject(String statementName,Object parameterObject)throws SQLExceptionpublic Object queryForObject(String statementName,Object parameterObject, Object resultObject)throws SQLExceptionpublic List queryForList(String statementName, Object parameterObject)throws SQLExceptionpublic List queryForList(String statementName, Object parameterObject,int skipResults, int maxResults)throws SQLExceptionpublic List queryForList (String statementName,Object parameterObject, RowHandler rowHandler)throws SQLExceptionpublic PaginatedList queryForPaginatedList(String statementName,Object parameterObject, int pageSize)throws SQLExceptionpublic Map queryForMap (String statementName, Object parameterObject,String keyProperty)throws SQLExceptionpublic Map queryForMap (String statementName, Object parameterObject,String keyProperty, String valueProperty)throws SQLException

在每种情况下一个映射声明的名称是在作为第一个参数传递。 这名对应的名称属性<声明>元素上面所描述的。 此外,一个参数对象总是可以可选地传递。 一个null参数对象可以通过如果没有参数的预期,否则它是必需的。 大部分的相似之处结束。 剩下的行为的不同概括如下。

4 3 5 1一个insert()、update()、delete():

这些方法都是专门为update语句(也称为非查询)。 据说,ita€™年代不可能执行update语句使用下面的查询方法,然而这是一个奇怪的语义和明显的司机的依赖。 对于executeUpdate(),该声明仅用于执行和返回受影响的行数。

4 3 5 2一个queryForObject():

有两个版本的executeQueryForObject(),返回一个新分配的对象,另一种方法使用一个预分配的对象作为参数传入。 后者是有用的对象,居住着超过一个语句。

4 3 5 3 a queryForList():

有三个版本的queryForList()。 第一个执行查询并返回所有的结果的查询。 第二个允许指定一个特定数目的结果被忽略(即一个起点)和最大数量的记录返回。 这是宝贵的在处理非常大的数据集,您并不希望返回完整的。

最后有一个queryForList()方法,它接受一个行处理程序。 这种方法允许您处理结果集排排但使用结果对象而不是通常的列和行。 该方法通过了典型的名称和参数对象,但是它还需要一个RowHandler。 行处理程序是一个类的实例,它实现了接口RowHandler。 这个接口RowHandler将只有一个方法如下:

public void handleRow (Object object, List list);
4 3 4 5 queryForPaginatedList():

这个非常有用的方法返回一个列表,可以管理数据的一个子集,用户可以通过后退前进。 这是常用于实现用户界面的一个子集,只显示所有可用的记录从查询返回。 一个例子是一个熟悉的大多数web搜索引擎发现10000支安打,但只显示一次。 PaginatedList接口包含的方法来浏览页面(全心全意()、previousPage(),gotoPage()),还检查页面的状态(isFirstPage(),isMiddlePage(),isLastPage(),isNextPageAvailable(),isPreviousPageAvailable(),getPageIndex()、getPageSize())。 尽管总记录数的可用不是可以在PaginatedList接口,这应该很容易实现通过简单地执行第二个语句,计数预期的结果。 过多的开销将相关PaginatedList否则。

4 3 5 5 a queryForMap():

这种方法提供了一种替代方法来加载一个集合到一个列表的结果。 相反它加载到一个映射的结果由参数传递进来的keyProperty。 例如,如果加载一组Employee对象,您可能将它们加载到一个映射键的财产employeeNumber。 地图上的值可以是整个employee对象,或另一个属性从employee对象中指定可选的第二个参数称为valueProperty。 例如,你可能只是想要一个员工姓名的地图由员工数量。 不要混淆了这个方法的概念使用映射类型作为一个结果对象。 可以使用此方法是否结果对象是一个JavaBean或者一个映射(或一个原始包装器,但这可能是无用的)。

4 3 5 6一个例子

ExampleA 57。 一个执行更新(插入、更新、删除)

sqlMap.startTransaction();Product product = new Product();product.setId (1);product.setDescription (“Shih Tzu”);int rows = sqlMap.insert (“insertProduct”, product);sqlMap.commitTransaction();

ExampleA 58。 一个执行查询对象(选择)

sqlMap.startTransaction();Integer key = new Integer (1);Product product = (Product)sqlMap.queryForObject (“getProduct”, key);sqlMap.commitTransaction();

ExampleA 59。 一个执行查询对象(选择)与预先分配结果对象

sqlMap.startTransaction();Customer customer = new Customer();sqlMap.queryForObject(“getCust”, parameterObject, customer);sqlMap.queryForObject(“getAddr”, parameterObject, customer);sqlMap.commitTransaction();

ExampleA 60。 一个执行查询列表(选择)

sqlMap.startTransaction();List list = sqlMap.queryForList (“getProductList”, null);sqlMap.commitTransaction();

61. ExampleA自动提交

// When startTransaction is not called, the statements will// auto-commit. Calling commit/rollback is not needed.int rows = sqlMap.insert (“insertProduct”, product);

62年ExampleA。 一个执行查询列表(选择)与结果边界

sqlMap.startTransaction();List list = sqlMap.queryForList (“getProductList”, null, 0, 40);sqlMap.commitTransaction();

63年ExampleA。 一个执行查询与一个RowHandler(选择)

public class MyRowHandler implements RowHandler {  public void handleRow (Object object, List list) throws    SQLException {      Product product = (Product) object;      product.setQuantity (10000);      sqlMap.update (“updateProduct”, product);      // Optionally you could add the result object to the list.      // The list is returned from the queryForList() method.    }  }  sqlMap.startTransaction();  RowHandler rowHandler = new MyRowHandler();  List list = sqlMap.queryForList (“getProductList”, null, rowHandler);  sqlMap.commitTransaction();}

64年ExampleA。 一个执行查询分页的列表(选择)

PaginatedList list =  sqlMap.queryForPaginatedList (“getProductList”, null, 10);list.nextPage();list.previousPage();

65年ExampleA。 一个执行查询映射

sqlMap.startTransaction();Map map = sqlMap.queryForMap (“getProductList”, null, “productCode”);sqlMap.commitTransaction();Product p = (Product) map.get(“EST-93”);

4.4。 一个课程的一页javabean

iBATIS数据映射框架需要公司了解javabean。 幸运的是,还有™年代€不多的JavaBeans API至于SqlMaps有关。 所以herea€™年代快速介绍JavaBeans如果你havena€™t被暴露在他们之前。

什么是对象? 一个JavaBean是一个类,坚持一个严格的命名方法,公约访问或变异状态的类。 另一种说法是,一个JavaBean遵循某些约定一个€œ得到一个€和一个€œsettinga€属性。 一个JavaBean的属性来定义它的方法定义(不是由它的字段)。 方法,从一个€这个词œ刚毛€是写能力属性(例如setEngine),而方法,首先€œ木屐€是可读的属性(例如getEngine)。 对于布尔属性的可读属性方法也可以从一个€这个词œisa€(如isEngineRunning)。 Set方法不应该定义一个返回类型(我。 e应该是void),应该只有一个单一的参数的适当类型的属性(如。字符串)。 Get方法应该返回适当的类型(如。字符串),并且应该不带任何参数。 尽管ita€™年代通常不执行,参数类型的设置方法和返回类型的get方法应该是相同的。 JavaBeans也应该实现Serializable接口。 JavaBeans也支持其他功能(事件等等),必须有一个无参数的构造函数,但这些都是不重要的上下文中的iBATIS数据映射器和通常同样不重要的上下文中的一个web应用程序。

据说,这里有一个例子,一个JavaBean:

66年ExampleA。 一个典型的JavaBean

public class Product implements Serializable {  private String id;  private String description;  public String getId() {    return id;  }  public void setId(String id) {    this.id = id;  }  public String getDescription() {    return description;  }  public void setDescription(String description) {    this.description = description;  }}

注意

小姐€™t混合数据类型的获取和设置属性对于一个给定的属性。 例如,对于一个数字一个€œaccounta€财产,一定要使用相同的数值类型的getter和setter,如下:

public void setAccount (int acct) {….}public int getAccount () {….}

注意到两个使用一个€œinta€类型。 返回一个一个€œ隆€从get方法,例如,会造成问题。

注意

同样,确保你只有一个方法命名getXxxx()和setXxxx()。 与多态方法是明智的。 “百度有啊€™再保险更好还是更特别的命名。 作为一个流:对于简单的只读二进制或文本数据。

注意

另一个getter语法存在对布尔类型属性。 get方法可能是命名格式的isXxxxx()。 要确保你要么有一个€œisa€方法或一个€œ木屐€方法,而不是两个!

祝贺你! “百度有啊€™已经通过该课程!

4.5。 一个日志SqlMap活动与Jakarta Commons日志

iBATIS数据映射框架提供了日志信息通过使用Jakarta Commons日志(JCL一个€“不是作业控制语言!)。 这个JCL框架提供了日志服务在一个实现独立的方式。 你可以一个€œ塞艾娜€各种测井提供者包括Log4J和JDK 1.4日志API。 Jakarta Commons日志记录的细节,Log4J和JDK 1.4日志API超出了本文的范围。 然而示例配置低于应该让你开始。 如果你想知道更多关于这些框架,你可以得到更多的信息从以下位置:

17为多。 一个日志记录框架支持通过iBATIS数据映射

Jakarta Commons日志http://jakarta.apache.org/commons/logging/index.htmlLog4jhttp://jakarta.apache.org/log4j/docs/index.htmlJDK 1.4日志APIhttp://java.sun.com/j2se/1.4.1/docs/guide/util/logging/

4.5.1。 一个日志配置

配置commons日志服务是非常简单的,包括一个或多个额外的配置文件(例如。 “log4j . properties”),有时一个新的JAR文件(例如,“将log4j . JAR”)。 下面的示例配置将配置完整日志服务使用Log4J作为一个提供者。 有两个步骤。

4 5 1 1。 步骤1:添加Log4J JAR文件

因为我们€™再保险使用Log4J,我们€™会需要确保它的JAR文件是可用于我们的应用程序。 记住,通用日志是一个抽象的API。 这并不意味着提供其实现。 所以使用Log4J,您需要将这个JAR文件添加到您的应用程序类路径。 您可以下载Log4J从URL之上或使用JAR中包含的iBATIS数据映射框架。 对于web或企业应用程序,您可以添加“log4j。 jar”到你的- inf / lib目录,或为一个独立的应用程序中,您可以简单地将它添加到JVM类路径启动参数,。

4 5 1 2。 步骤2:配置Log4J

配置Log4J很简单。 像通用日志,百度™€会再添加一个属性文件到您的classpath根(即不包)。 这一次的文件被称为log4j。 属性和它看起来如下:

ExampleA 67.一个log4j . properties

1  # Global logging configuration2  log4j.rootLogger=ERROR, stdout3  # SqlMap logging configuration...4  #log4j.logger.com.ibatis=DEBUG5  #log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG6  #log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG7  #log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG8  #log4j.logger.java.sql.Connection=DEBUG9  #log4j.logger.java.sql.Statement=DEBUG10 #log4j.logger.java.sql.PreparedStatement=DEBUG11 #log4j.logger.java.sql.ResultSet=DEBUG12 # Console output...13 log4j.appender.stdout=org.apache.log4j.ConsoleAppender14 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout15 log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

上述文件是最小的配置,将导致日志记录只报告错误。 文件的第二行是什么是显示配置Log4J只报告错误到stdout appender。 一个appender是一个组件,收集输出(如控制台、文件、数据库等等)。 以最大程度的报告,我们可以改变第2行如下:

log4j.rootLogger=DEBUG, stdout

通过改变2号线为以上,Log4J现在将报告所有记录的事件的一个€˜stdouta€™appender(控制台)。 如果你想调优日志记录在一个好的层面,你可以配置的每个类日志系统使用一个数据映射器日志configurationa€˜€™部分上述文件(注释掉的行5到12以上)。 所以如果我们想日志PreparedStatement活动(SQL语句)到控制台的调试级别,我们将简单地改变第11行到以下(注意ita€™不是#注释掉了):

log4j.logger.java.sql.PreparedStatement=DEBUG

剩余的配置在log4j。 属性文件是用来配置appender,这超出了本文的范围。 然而,你可以找到更多的信息在Log4J网站(URL以上)。 或者,你可以简单地玩它,看看效果不同的配置选项。

4.6。 一个SimpleDataSource(com ibatis普通jdbc . *)

这个SimpleDataSource类是一个简单的实现的JDBC 2.0兼容的数据源。 它支持一个方便的设置连接池特性和完全同步(没有衍生线程),这使得它非常轻量级和便携式连接池的解决方案。 使用SimpleDataSource完全像任何其他JDBC DataSource的实现,并记录作为JDBC标准扩展API,它可以在这里找到:http://java.sun.com/products/jdbc/jdbc20.stdext.javadoc/

注意

JDBC 2.0 API现在包括作为一个标准部分J2SE 1 4 x

注意

SimpleDataSource很方便,高效的和有效的。 然而,对于大型企业或关键任务的应用程序,推荐您使用企业级DataSource的实现(例如那些有应用服务器和商业O / R映射工具)。

SimpleDataSource的构造函数需要一个属性参数,需要一些配置属性。 下面的表名称和描述的属性。 只有一个€œJDBC。 一个€属性是必需的。

为多18。 一个SimpleDataSource属性

属性名需要默认描述[:TODO:]   

68年ExampleA。 一个使用SimpleDataSource

DataSource dataSource = new SimpleDataSource(props); //properties usually loaded from a fileConnection conn = dataSource.getConnection();//…..database queries and updatesconn.commit();conn.close(); //connections retrieved from SimpleDataSource will return to the pool when closed

4.7。 一个ScriptRunner(com ibatis普通jdbc . *)

这个ScriptRunner类是一个非常有用的工具运行SQL脚本,可以做诸如创建数据库模式或插入违约或测试数据。 而不是讨论ScriptRunner长,考虑下面的示例,说明如何简单,它是使用。

69年ExampleA。 一个脚本:initializeHere是一些例子:db sql

-- Creating Tables – Double hyphens are comment linesCREATE TABLE SIGNON (USERNAME VARCHAR NOT NULL, PASSWORD VARCHAR NOTNULL, UNIQUE(USERNAME));-- Creating IndexesCREATE UNIQUE INDEX PK_SIGNON ON SIGNON(USERNAME);-- Creating Test DataINSERT INTO SIGNON VALUES('username','password');

70年ExampleA。 一个使用方法:使用一个现有连接

Connection conn = getConnection(); //some method to get a ConnectionScriptRunner runner = new ScriptRunner ();runner.runScript(conn, Resources.getResourceAsReader("com/some/resource/path/initialize.sql"));conn.close();

71年ExampleA。 一个使用:用一个新的连接

ScriptRunner runner = new ScriptRunner (“com.some.Driver”, “jdbc:url://db”, “login”, “password”);runner.runScript(conn, new FileReader("/usr/local/db/scripts/ initialize-db.sql"));

72年ExampleA。 一个使用2:使用一个新的连接从属性

Properties props = getProperties (); // some properties from somewhereScriptRunner runner = new ScriptRunner (props);runner.runScript(conn, new FileReader("/usr/local/db/scripts/ initialize-db.sql"));

properties文件(地图)上述示例中使用必须包含以下属性:

driver=org.hsqldb.jdbcDriverurl=jdbc:hsqldb:.username=dbapassword=whateverstopOnError=true

一些方法,你会发现有用的是:

// if you want the script runner to stop running after a single errorscriptRunner.setStopOnError (true);// if you want to log output to somewhere other than System.outscriptRunner.setLogWriter (new PrintWriter(…));

4.8。 一个资源(com ibatis共同资源。*)

资源类提供的方法使它很容易从类路径加载资源。 处理类加载器是具有挑战性的,尤其是在一个应用程序服务器/容器。 资源类试图简化处理这有时冗长乏味的任务。

共同使用的资源文件有:

加载数据映射器配置文件(如。 “sqlMap-config.xml”)从类路径中一个加载DAO管理器配置文件(如。 “刀xml”)从类路径加载各种*。 属性文件从类路径。等等。

有许多不同的方法来加载一个资源,包括:

作为一个读者:对于简单的只读文本数据。作为一个流:对于简单的只读二进制或文本数据。作为一个文件:对于读/写二进制或文本文件。作为一个属性文件:对于只读配置属性文件。作为一个URL:对于只读通用资源

各种方法的资源类加载资源使用上述任何一个方案如下(为了):

Reader getResourceAsReader(String resource);Stream getResourceAsStream(String resource);File getResourceAsFile(String resource);Properties getResourceAsProperties(String resource);Url getResourceAsUrl(String resource);

在每种情况下,类加载器被用来加载资源将是相同的,其加载资源类,或当失败,系统类装入器将被使用。 如果你是在一个环境中,类加载器是麻烦(例如在某些应用服务器),您可以指定要使用的类加载器(例如使用类加载器从一个你自己的应用程序类)。 上述每个方法有一个妹妹方法,它接受一个类加载器作为第一个参数。 它们是:

Reader getResourceAsReader (ClassLoader classLoader, String resource);Stream getResourceAsStream (ClassLoader classLoader, String resource);File getResourceAsFile (ClassLoader classLoader, String resource);Properties getResourceAsProperties (ClassLoader classLoader, String resource);Url getResourceAsUrl (ClassLoader classLoader, String resource);

资源命名的资源参数应该是完整的包名称加上完整的文件/资源名称。 例如,如果你有一个资源在您的类路径€˜com.domain.mypackage.MyPropertiesFile等。 propertiesa€™,你可以负载作为一个属性文件使用资源类使用以下代码(注意,资源不首先削减一个€œ/一个€):

String resource = “com/domain/mypackage/MyPropertiesFile.properties”;Properties props = Resources.getResourceAsProperties (resource);

同样你可以加载您的数据映射器配置文件从类路径作为一个读者。 说ita€™年代在一个简单属性包类路径(“properties.sqlMap-config.xml”):

String resource = “properties/sqlMap-config.xml”;Reader reader = Resources.getResourceAsReader(resource);SqlMapClient sqlMap = XmlSqlMapBuilder.buildSqlMap(reader);

5.。 净开发者指南

本指南解释如何安装、配置和使用iBATIS数据映射器与你的。 网络应用程序。 本指南假定您正在使用微软Visual Studio。 净(VSN)。 如果您使用的是另一个IDE,请相应地调整这些指令。

5.1。 一个安装数据映射为。net

有三个步骤来使用iBATIS数据映射器与应用程序第一次。

  1. 设置分布
  2. 添加程序集引用
  3. 添加XML文档

5.1.1。 一个设置分布

官方网站为iBATIS数据映射为。 网络是我们的SourceForge网站< http://ibatisnet.sf.net/ >。 下载分布,根据链接文件区域,并选择iBATIS。 净V1.0或更高版本。 分布的形式是一个ZIP归档。 您可以使用一个实用程序提取分布,像WinZip,或者(如果你必须)器构建到新版本的Windows。 我们建议您创建一个“ibatisnet”文件夹在你的VSN项目目录并提取分布那里。

在分布的“源”文件夹中有五个其他文件夹,构成了iBATIS。 净分布,显示在表19。

为多19。 一个文件夹中发现的iBATIS。 净分布

外部本预编译的程序集提供了,为了您的方便。IBatisNet-Common装配类DataAccess和DataMapper共享IBatisNet-DataAccess数据访问对象框架(请参阅单独的DAO指南)iBatisNet-DataMapper数据映射框架IBatisNet-TestNUnit测试解决方案

你可以IBatisNet加载”。 sln”解决方案文件到Visual Studio和构建解决方案来生成所需的程序集。 有四个项目在解决方案,都应该成功。 我们需要的组件将被创建在“\源\ IBatisNet.DataMapper \ bin \调试”。 创建的组件是:IBatisNet.Common。 dll,iBatisNet.DataAccess。 dll,并iBatisNet.DataMapper。 dll。

5.1.2中所述。 一个程序集引用添加

切换到您自己的解决方案,打开项目,将使用iBATIS。 净数据映射。 这取决于你如何组织你的解决方案,这可能不是项目你的Windows或Web应用程序。 它可能是一个库项目,您的应用程序项目引用。 你的项目,你需要添加两个或三个引用:

  1. iBatisNet.DataMapper.dll
  2. iBatisNet.Common。 dll(暗示)
  3. iBatisNet.DataAccess。 dll(可选)

如果您使用的是Mapper singleton(见节5 3 1),那么唯一的参考你可能需要到DataMapper装配。 常见的装配仍然是需要的,但Visual Studio网将为您解决依赖性。 如果您使用数据访问对象框架,那么你将需要一个参考传给DataAccess装配太。 所以,开始了第一个,并添加其他的只有如果需要。

如果你已经建立了iBatisNet溶液中描述的部分5.1.1,所有三个组件应该位于bin / Debug文件夹在iBatisNet-DataMapper项目。

5.1.3。 一个XML文件中添加条目

您将需要添加三个或三个以上的XML文件条目到你的Windows或Web应用程序项目(和测试项目,如果你有一个)。 这些文件是:

SqlMap。 config -数据映射器配置文件(通常是一个)SqlMap。 xml——数据映射定义文件(通常是一个或多个,各种名称)提供者。 config -数据库供应商定义文件。

“SqlMapper。 配置”和“提供者。 配置”文件必须放置在框架可以在运行时找到他们。 默认位置的不同类型的项目,见表20。

为多20。 一个SqlMap的位置。 配置文件

Windows、图书馆、或测试项目(使用NUnit或等效)发生在/ bin / Debug文件夹,组装(. dll)文件,与“应用程序配置”文件Web项目在项目根的地方,“网络。 配置”文件

“SqlMapper。 配置”文件包含一个引用您的数据映射定义文件(如。 “SqlMap.xml”)。 你可能希望把映射定义在一个文件夹名为“地图”或“资源”,然后引用中的映射形式”资源= /资源/帐户xml”。 资源引用是相对于“项目根”,所以它可以是相同的,不管哪个配置文件被放置。

您还可以使用绝对路径,您的数据映射定义文件,如果这是更方便。 使用url属性相反,在表单”uri = " file:/ / / C:/项目/ MySolution / MyProject /地图/ SqlMap.xml“,和替代路径到您自己的映射文件。

当然,“SqlMapper。 配置”文件必须以正确的格式,这是第5.2节中描述。 地图数据的格式(“SqlMap的描述。 xml”文件)被第三节。

5.2。 一个配置数据映射为。net

iBATIS数据映射器配置使用一个中央的XML描述符文件,通常命名为“SqlMapper。 配置”,它提供了详细的为你的数据源、数据地图,和其他的一些功能,比如缓存,事务和线程管理。 在运行时,您的应用程序代码调用一个iBATIS库例程(见5.3节),读取和解析主要配置文件。 其他XML描述符可以被引用,但是每个数据映射器客户端实例“靴”从一个配置文件。

5 2 1。 一个数据映射器客户

每个数据映射器客户机(实例的SqlMapper)是由阅读一个配置文件。 每个配置文件可以指定一个数据库或数据源。 然而,你可以使用多个数据映射器客户在您的应用程序。 只是创建另一个配置文件,该文件的名称传递数据映射器客户机创建的。 配置文件可能使用一个不同的帐户与相同的数据库,或者引用不同的数据库在不同的服务器上。 你甚至可以读和写从一个客户到另一个,如果这就是你需要做的。

5.2.2。 一个数据映射器配置文件(SqlMapper.config)

一个示例配置文件。 73年净显示在示例。

ExampleA SqlMap 73.。 配置为。net

<?xml version="1.0" encoding="utf-8"?> <sqlMapConfig   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xsi:noNamespaceSchemaLocation="http://ibatisnet.sf.net/schemaV1/SqlMapConfig.xsd"> <properties resource="/Resources/database.properties"/> <settings>  <setting useFullyQualifiedStatementNames="false"/>  <setting cacheModelsEnabled="true"/> </settings> <database>  <provider name="sqlServer1.1"/>  <dataSource name="NPetshop"    connectionString="     user id=${username};     password=${password};     data source=${datasource};     database=${database};     connection reset=false;     connection lifetime=5;     min pool size=1;     max pool size=50"/> </database> <alias>  <typeAlias alias="Account" assembly="IBatisNet.Test.dll" type="IBatisNet.Test.Domain.Account"/> </alias> <sqlMaps>  <sqlMap resource="/Resources/Category.xml"/>  <sqlMap resource="/Resources/Product.xml"/></sqlMaps> </sqlMapConfig>

5 2 3。 一个数据映射器的配置元素

部分5 1 3 1通过5 1 3 8描述了数据元素映射器配置文件为。net。

5 2 3 1。 一个<属性>元素

有时我们使用的值在一个XML配置文件出现在不止一个元素。 通常,有价值,当我们移动应用程序的更改从一个服务器到另一个。 帮助你管理的配置值,您可以指定一个标准的属性文件(名称=值)的一部分,一个数据映射器配置。 每一个名为value的属性文件变成了一个“壳”变量,可应用于整个数据映射器配置,包括数据映射定义文件(参见第三节)。例如,如果属性文件包含

<add key="username" value="albert" />

然后任何元素的数据映射器配置,包括数据映射,可以使用变量$ { username }插入值“iBATIS”。 例如:

<dataSource connectionString="user id=${username}; 

属性是方便的在构建、测试和部署。 性能使它容易重新配置您的应用程序的多个环境或使用的自动化工具的配置(如。NAnt)。

5 2 3 1 1。 一个<属性>属性

只可以有一个<属性>元素,可以接受一个必要属性,“资源”,是一个属性文件的路径。

5 2 3 2。 一个<设置>元素

有两种框架使用了默认设置。 (至少现在。) 设置适合一个应用程序可能不适合另一个。 <设置>元素允许您配置这些选项和优化的数据映射器实例创建的XML文档。 每有一个默认的设置,您可以省略这个设置元素或它的任何属性。 设置属性和行为描述他们控制表21。

为多21。 一个属性的设置元素

cacheModelsEnabled

这个设置全局启用或disidables所有缓存模型为一个SqlMapClient。 这对调试可以派上用场。

Example: cacheModelsEnabled=”true”Default: true (enabled)

useStatementNamespaces

与启用该设置,您必须总是把映射声明他们的完全限定名称,它是namesource sqlMap的组合和语句id。例如:queryForObject(一个€œNamespace.statementIda€);

Example: useStatementNamespaces=”false”Default: false (disabled)
5 2 3 3。 一个< typeAlias >元素

这个typeAlias元素允许您指定一个简短的名字代替完全限定类名。 例如:

  <typeAlias alias="LineItem" assembly="NPetshop.Domain.dll" class="NPetshop.Domain.Billing.LineItem" />

然后您可以参阅“帐户”或“账户”在你经常不得不拼出的完全限定类名。

注意

在。 净实现,零个或多个< typeAlias >元素可以出现在数据映射定义文件,在一个封闭的<别名>元素。

5 2 3 3 1。 一个< typeAlias >属性

< typeAlias >元素有三个属性:

别名——这个元素的惟一标识符装配——这个名字的装配,阶级居住——完全限定类名,包括名称空间引用
5 2 3 3 2。 一个预定义的类型别名

这个。 网络平台预定义了一些别名,您可以使用在您的数据映射器配置文件,见表22。

为多22。 一个预定义的别名

别名classnameHashtable系统集合hashtableTODO:别人? int ? 
5 2 3 4。 一个<提供者>元素

在ADO。 网,一个数据库系统是通过一个提供者。 一个数据库系统可以使用一个自定义服务提供方程序或一个通用的ODBC提供者。 iBATIS。 使用一个可插的净方法来安装提供者。 每个提供者都代表一个XML描述符元素。 提供者列表中你可能想要使用可以保存在一个单独的XML描述符文件。 iBATIS。 净分布包含一个标准的“提供者。 配置”文件,一组六个预先写的提供者要素:

状态"置疑" 1.0状态"置疑" 1.1OleDb 1.1(访问)ODBC 1.1 idOracle 9.2ByteFx(MySQL)

标准的“提供者。 配置”文件可以发现在“\ \ IBatisNet来源。 测试\ bin \调试“iBATIS。 净分布(见5.1节)。 使用它,您必须将它复制到您的项目,包括一个相对文件参考在<提供者>元素。

一个提供者可能需要的库,你没有安装,那么提供者元素允许您禁用未使用的提供者。 一个提供者也可以被标记为“缺省”,将被用于如果没有指定另一个由您的配置(参见节5 2 3 5)。

标准的“提供者。 配置”文件设置为默认状态"置疑" 1.1,1.0提供者禁用状态"置疑"。 Oracle和ByteFx提供商也被禁用。 (甲骨文是专有软件,ByteFx船只在一个更宽松的许可证)。

重要

ByteFx是推荐的提供者如果您使用的是MySQL。 你可以下载ByteFx从MySQLNet SourceForge网站(http://sf.net/projects/mysqlnet/)。 如果ByteFx许可证是可以接受的,你可以将它安装在您的应用程序作为一个参考,使ByteFx提供者。 ByteFx将加入MySQL项目并将可在那里。

提示

确保检查“提供者。 配置”文件,并确认该提供者你打算使用启用了! (设置激活属性为true)。

5 2 3 5。 一个<数据库>元素

<数据库>元素包含元素,配置数据库系统使用的框架。 这些是<提供者>、< datasource >和< transactionManager >元素。

5 2 3 5 1。 一个<提供者>元素

如果默认提供者正在被使用,<提供者>元素是可选的。 或者,如果多个提供者是可用的,一个可能选择使用提供者元素,在不改变“提供者。 配置”文件。

<provider name="OleDb1.1"  />
5 2 3 5 2。 一个< datasource >元素

< datasource >元素指定ODBC数据源或连接字符串。 示例显示了示例元素用于SQL 74服务器,甲骨文、访问和MySql。

74年ExampleA。 一个示例< datasource >和<提供者>元素(. net)

<!-- The ${properties} are defined in an external file, --><!-- but the values could also be coded inline. --><!-- Connecting to SQL Server --><database>  <provider name="sqlServer1.1" />  <dataSource name="NPetstore" default="true"     connectionString="data source=(local)\NetSDK;database=${database};    user id=${username};password=${password};connection reset=false;    connection lifetime=5; min pool size=1; XML descriptor filesmax pool size=50"/></database>id<!-- Connecting to Oracle -->TODO: <!-- Connecting to Access --><database>  <provider name="OleDb1.1" />  <dataSource name="NPetstore" default="true"     connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=${database}"/></database><!-- Connecting to a MySQL database --> <database>  <provider name="ByteFx" />  <dataSource name="NPetstore" default="true"     connectionString="Host=${host};Database=${database};    Password=${password};Username=${username}" /></database>
5 2 3 5 3。 一个< transactionManager >元素(TODO:实现]

这个。 净实现只支持ado控制事务,这是平台违约。 未来的版本可能支持COM +事务(通过服务没有组件)。

5 2 3 6。 一个< sqlMap >元素

每天,你的大部分工作将与数据映射,这是覆盖着第三节。 数据映射定义实际的SQL语句或存储过程使用的应用程序。 参数和结果对象也定义为数据地图的一部分。 随着应用程序的增长,你可能会有几个种类的数据地图。 帮助你保持你的数据地图有组织的,您可以创建任意数量的数据映射定义文件并将它们通过引用到数据映射器配置。 所有的定义文件使用一个数据映射器实例必须在配置文件中列出。

示例显示了< sqlMap > 75元素加载一组数据映射定义。 注意,< sqlMap >元素是嵌套在< sqlMaps >元素。

75年ExampleA。 一个SqlMap元素

<sqlMaps>  <sqlMap resource="/Resources/Category.xml"/>  <sqlMap resource="/Resources/Product.xml"/></sqlMaps>

更多关于数据映射定义文件,请参阅第3部分。

5 2 3 7。 一种迁移从版本0 9 x

[TODO:升级指南]

5.3。 一个编程和iBATIS数据映射器:。 净API

iBATIS。 净数据映射器API提供了四个核心功能:

  1. 建立一个SqlMapper实例从一个配置文件

  2. 执行一个update查询(包括插入和删除)。

  3. 执行一个select查询一个对象

  4. 执行一个select查询对象的一个列表

API还支持分页检索列表和管理事务。

5 3 1。 一个构建一个SqlMapper实例

XML文档是一个神奇的工具来描述一个数据库配置(5.2节)或定义一组数据映射(第3部分),但是你不能“执行”XML。 为了使用iBATIS。 网络配置和定义你。 网络应用程序,您需要一个类可以调用。

该框架提供了服务方法,您可以调用读取配置文件(和它的任何定义文件),并构建一个“SqlMapper”对象。 这个SqlMapper对象提供了访问其他的框架。 这个SqlMapper被设计成多线程和长寿,因此成为一个优秀的单例。 示例显示了一个单例映射器,76是附带的框架。

76年ExampleA。 一个一个Mapper singleton可以调用从您自己的应用程序

using IBatisNet.Common.Utilities;using IBatisNet.DataMapper;namespace IBatisNet.DataMapper{ public class Mapper {    private static volatile SqlMapper _mapper = null;  protected static void Configure (object obj)  {   _mapper = (SqlMapper) obj;  }  protected static void InitMapper()  {      ConfigureHandler handler = new ConfigureHandler (Configure);   _mapper = SqlMapper.ConfigureAndWatch (handler);  }  public static SqlMapper Instance()  {   if (_mapper == null)   {    lock (typeof (SqlMapper))    {     if (_mapper == null) // double-check      InitMapper();    }   }   return _mapper;  }  public static SqlMapper Get()  {   return Instance();  } }}

获得SqlMapper实例,就叫

SqlMapper mapper = Mapper.Instance();

在您的应用程序的任何地方,并指定SqlMapper方法之一(见节5 3 2)。 这里的一个例子:

IList list = Mapper.Instance() .QueryForList ("PermitNoForYearList", values);

第一次“映射器实例() “被调用时,它将读取缺省配置文件,“SqlMap.config”。 在随后的调用,它将使用缓存“映射”实例。 这个方法监测变化ConfigureAndWatch配置文件。 如果配置或定义文件改变了,SqlMapper会安全重新加载。 这是特别有用的在开发时,您可能会更改数据映射定义,希望看到它生效不重新启动调试会话。 同样,在生产中,它可以让你修改定义,而不用重新加载应用程序的其余部分。

注意

如果您使用的是NUnit测试你的映射,您可以运行一个测试套件,更改XML映射文件,并再次运行测试。 NUnit会自动重新加载配置。

注意

如果你改变一个映射文档而web应用程序正在运行,您可能需要重新启动web服务器加载之前新配置。 一个简单的方法是把一个快捷方式到服务applet在你的桌面上。

如果因为某些原因你不希望监视更改配置,您可以创建自己的“映射”类,并使用配置方法相反:

mapper = SqlMapper.Configure(handler);
5 3 1 1。 一个多个数据库

如果你需要访问多个数据库从相同的应用程序,创建一个数据映射器配置类,数据库和另一个“映射”类去用它。 在新的“映射”类,改变调用ConfigureAndWatch来

mapper = SqlMapper.ConfigureAndWatch("anotherConfig.config",handler);

和替补配置类的名称。 每个数据库然后有自己的单例可以调用从您的应用程序:

SqlMapper sqlServer = SqlServerMapper.Get();SqlMapper access = AccessMapper.Get();

5 3 2。 一个探索SqlMapper API

SqlMapper实例的行为像一个facade提供访问其余的数据映射框架。 数据映射器API方法显示在77年的例子。

77年ExampleA。 一个数据映射器API,用于。net

<!-- Query API -- see Sections 5.3.2.1 through 5.3.2.5 -->public object Insert(string statementName, object parameterObject);public int Update(string statementName, object parameterObject);public int Delete(string statementName, object parameterObject);public object QueryForObject(string statementName, object parameterObject);public object QueryForObject(string statementName, object parameterObject, object resultObject);public IList QueryForList(string statementName, object parameterObject);public void QueryForList(string statementName, object parameterObject, IList resultObject);public IList QueryForList(string statementName, object parameterObject, int skipResults, int maxResults);public IList QueryWithRowDelegate(string statementName, object parameterObject, RowDelegate rowDelegate);public PaginatedList QueryForPaginatedList(String statementName, object parameterObject, int pageSize);public IDictionary QueryForDictionary(string statementName, object parameterObject, string keyProperty)public IDictionary QueryForDictionary(string statementName, object parameterObject, string keyProperty, string valueProperty)public IDictionary QueryForMap(string statementName, object parameterObject, string keyProperty)public IDictionary QueryForMap(string statementName, object parameterObject, string keyProperty, string valueProperty)<!-- Transaction API -- see Section 5.3.3 -->public void BeginTransaction() public BeginTransaction(IsolationLevel isolationLevel)public void CommitTransaction()public void RollBackTransaction()

请注意,每个API方法接受名称的映射语句作为第一个参数传递。 statementName对应的参数ID映射的语句的数据映射定义(见节3 2 4 1)。 在每一种情况下,parameterObject也可能被传递。 如果没有参数映射的声明预计,一个空parameterObject可能被传递。 如果一个语句并期望参数,然后一个有效的parameterObject是必需的。 部分5 3 2 1通过5 3 2 5描述如何工作的API方法。

5 3 2 1。 一个插入、更新、删除
public object Insert(string statementName, object parameterObject);public int Update(string statementName, object parameterObject);public int Delete(string statementName, object parameterObject);

如果一个映射语句使用一个< insert >、< update >或<删除>声明类型,那么它应该使用相应的API方法。 < insert >元素支持一个嵌套的< selectKey >元素生成主键(见节3 2 3 2)。 如果< selectKey >节被使用,然后插入返回生成的关键;否则null。 这两个更新和删除返回的行数影响。

5 3 2 2一个QueryForObject
public object QueryForObject(string statementName, object parameterObject);public object QueryForObject(string statementName, object parameterObject, object resultObject);

如果一个映射的声明预计将选择一个单独的行,然后使用QueryForObject调用它。 自映射的语句定义指定结果类预期,该框架既可以创建和填充结果类给你。 或者,如果您需要管理结果对象自己,说因为它被居住着超过一个语句中,您可以使用替代形式,通过你的resultObject作为第三个参数。

5 3 2 3 a QueryForList
public IList QueryForList(string statementName, object parameterObject);public void QueryForList(string statementName, object parameterObject, IList resultObject);public IList QueryForList(string statementName, object parameterObject, int skipResults, int maxResults);

如果一个映射的声明预计将选择多个行,然后使用QueryForList调用它。 列表中的每个条目将一个结果对象填充相应的排的查询结果。 如果您需要管理resultObject自己,那么它可以通过第三个参数。

如果您需要获得一个部分结果,第三种形式需要的记录的数目跳过(起点)和最大数量返回,因为skipResults和maxResults参数。 这个PaginatedList方法(部分5 3 2 5)提供相同的功能,但在一个更方便的包装器。 这个QueryWithRowDelegate方法(部分5 3 2 4)也适用于多个行,但提供了一个后期处理功能。

5 3 2 4 a QueryWithRowDelegate
public delegate void RowDelegate(object obj, IList list);public IList QueryWithRowDelegate(string statementName, object parameterObject, RowDelegate rowDelegate);

无论多么好我们的数据库设计,或如何巧妙我们描述我们的地图,我们回来的结果对象可能不是最理想的。 您可能需要执行一些后期处理任务的结果对象。 你甚至可能想省略一个条目从列表中省略了。 或者,您可能希望使用结果对象创建其他一些、更有用的对象。 节省过滤结果对象从一个到另一个列表,您可以通过iBATIS。 网一个RowDelegate去做肮脏的工作。 代表将被传递反过来每个结果对象和IList参考。 你的委托可以应对对象,并添加到列表,如果适当的。

重要

这是你的责任,你想要添加对象返回到列表。 如果一个对象并不是说它不返回。

5 3 2 5 a QueryForPaginatedList
public PaginatedList QueryForPaginatedList(String statementName, object parameterObject, int pageSize);

我们生活在一个信息时代溢出。 一个数据库查询通常返回更多的打击比用户希望看到在一次,和我们的需求可能会说,我们需要提供一长串的结果一次“页面”。 如果查询返回1000的点击量,我们可能需要向用户呈现打在套五十,让他们之间来回移动的设置。 既然这是一个常见的需求,这个框架提供了一种方便的方法。

PaginatedList接口包含的方法来浏览页面(全心全意()、previousPage(),gotoPage()),还检查页面的状态(isFirstPage(),isMiddlePage(),isLastPage(),isNextPageAvailable(),isPreviousPageAvailable(),getPageIndex()、getPageSize())。 尽管总记录数的可用不是可以在PaginatedList接口,这应该很容易实现通过简单地执行第二个语句,计数预期的结果。 过多的开销将相关PaginatedList否则。

提示

PaginatedList的方法是方便的,但是请注意,一个更大的集将首先被数据库返回的提供者和小集提取的框架。 更高的页面,较大的组,将被返回并被丢弃。 对于非常大的集合,您可能想要使用一个存储过程或您自己的查询,使用“skipResults”和“maxResults”作为参数。 不幸的是,语义返还部分数据集不是标准化的,所以PaginatedList是我们能够做到的最早的范围内的一个框架。

5 3 2 6。 一个QueryForDictionary,QueryForMap
public IDictionary QueryForDictionary(string statementName, object parameterObject, string keyProperty)public IDictionary QueryForDictionary(string statementName, object parameterObject, string keyProperty, string valueProperty)public IDictionary QueryForMap(string statementName, object parameterObject, string keyProperty)public IDictionary QueryForMap(string statementName, object parameterObject, string keyProperty, string valueProperty)

QueryForList方法返回的结果对象在一个IList实例。 或者,QueryForDictionary返回一个IDictionary实例。 每个条目的值是一个结果对象。 每个条目的关键表示keyProperty参数。 这是名称的属性的一个结果对象,其价值是用作键为每个条目。 例如,如果你需要一组Employee对象,您可能希望他们返回为一个IDictionary由每个对象的EmployeeNumber属性。

如果你不需要整个结果对象在你的字典,你可以添加valueProperty参数来表示,结果对象属性应该是一个条目的值。 例如,您可能只希望EmployeeName由EmployeeNumber。

重要

您不需要使用这个方法只是为了获得一个IDictionary结果对象。 正如3.节中x x。 ,对于任何查询结果对象可以是一个属性对象或一个IDictionary实例。 该方法用于生成一个IDictionary结果对象从一个属性对象或(另一个)IDictionary对象。 在这种情况下,关键是一个属性指定,这个值是行从结果集。

QueryforMap方法提供相同的功能,但在一个不同的名称,为了连续性与Java实现。 (。 净IDictionary接口相当于Java映射接口)。

5 3 3。 一个使用显式的和自动交易

默认情况下,调用任何API方法(见节5 3 2)在一个SqlMapper实例将自动提交/回滚作为一个单独的事务。 这意味着每次调用这些方法将一个单一的工作单元。 对于许多情况下,这种简单的方法可能就足够了。 但这不是理想的,如果你有一个数量的语句,必须执行作为一个单一的工作单元,也就是说,成功或失败作为一个群体。 对于这些情况下,您可以使用显式事务

数据映射器API包括方法划分事务界限。 一个事务可以启动、提交和/或回滚。 你可以叫事务方法SqlMapper实例(见节5 3 1)。

public void BeginTransaction()public void BeginTransaction(IsolationLevel isolationLevel)  public void CommitTransaction()public void RollBackTransaction()

通过开始一个事务你检索连接池连接的,开放它接收SQL查询和更新。

使用事务的一个例子是78年表现为例。

78年ExampleA。 一个使用显式的交易

[TODO:]

注意

事务不能嵌套。 将抛出一个异常,如果你叫BeginTransaction从同一线程不止一次或调用CommitTransaction或RollbackTransaction第一。 换句话说,每个线程都可以在大多数一个事务中打开,每SqlMapper实例。

注意

SqlMap事务使用ThreadLocal存储来存储事务对象。 这意味着每个线程调用BeginTransaction将得到一个独特的连接对象为他们的事务。 唯一的方法返回一个连接到数据源(或关闭连接)是调用CommitTransaction。 不这样做可能会导致您的池耗尽连接和锁定。

5 3 3 1。 一个自动交易

最好是使用显式的交易。 但对于简单的需求(通常是只读的,您可以使用一个简化的语义。 如果你不限定查询API语句使用*事务方法,这些交易都将被自动给你当你执行一个语句块之外的事务。 看到例子为一个自动交易79。

79年ExampleA。 一个依赖自动交易

[TODO:]

注意

小心你的查询时考虑事务框架。 自动交易是很方便的,但是你将遇到困难,如果你的工作单元需要超过一个更新到数据库。 在示例56,如果第二个调用一个€œupdateItema€失败,项目描述仍将更新为第一个新的描述一个€œTX1a€。 不是一个用户可能期望。

5 3 4。 一个编码示例[TODO:扩大在一个食谱的实际例子)

80年ExampleA。 一个执行更新(插入、更新、删除)

Product product = new Product();product.Id = 1;product.Description = “Shih Tzu”;int key = sqlMap.Insert (“insertProduct”, product);

81年ExampleA。 一个执行查询对象(选择)

int key = 1;Product product = sqlMap.QueryForObject (“getProduct”, key) as Product;

82年ExampleA。 一个执行查询对象(选择)与预先分配结果对象

Customer customer = new Customer();sqlMap.BeginTransaction();sqlMap.QueryForObject(“getCust”, parameterObject, customer);sqlMap.QueryForObject(“getAddr”, parameterObject, customer);sqlMap.CommitTransaction();

83年ExampleA。 一个执行查询列表(选择)

IList list = sqlMap.QueryForList (“getProductList”, null);

84. ExampleA自动提交

// When startTransaction is not called, the statements will// auto-commit. Calling commit/rollback is not needed.int key = sqlMap.Insert (“insertProduct”, product);

85年ExampleA。 一个执行查询列表(选择)与结果边界

List list = sqlMap.queryForList (“getProductList”, null, 0, 40);

86年ExampleA。 一个执行查询与一个RowHandler(选择)

  public void RowHandler(object obj, IList list)  {       Product product = (Product) object;       product.Quantity = 10000;  }  SqlMapper.RowDelegate handler = new SqlMapper.RowDelegate(this.RowHandler);  IList list = sqlMap.QueryWithRowDelegate("getProductList", null, handler);  }

87年ExampleA。 一个执行查询分页的列表(选择)

PaginatedList list = sqlMap.QueryForPaginatedList (“getProductList”, null, 10);list.NextPage();list.PreviousPage();

88年ExampleA。 一个执行查询映射

IDictionary map = sqlMap.QueryForMap (“getProductList”, null, “productCode”);Product p = (Product) map[“EST-93”];

5.4。 一个日志SqlMap活动与Apache Log4Net

iBATIS数据映射框架提供了日志信息通过使用Apache Log4Net(http://logging.apache.org/log4net/)。 Log4Net的细节超出了本文的范围。 本节提供了一个示例配置来帮助你开始。

5.4.1之前。 一个日志配置

这个框架使用了Log4Net内部和将自动包括组装当你的项目是建立。 使用Log4Net与您自己的应用程序,您只需要提供您自己的Log4Net配置。 为此,您可以添加一个配置文件,为您的程序集包含一个log4Net元素。 配置文件命名您的程序集,但是增加了。 配置扩展,并存储在相同的文件夹中为您的程序集。 示例显示了配置89框架的测试项目。

89年ExampleA。 一个示例Log4Net配置块(IBatisNet.Test.dll.Config)

<configuration> <!-- Register a section handler for the log4net section --> <configSections>  <section name="log4net" type="System.Configuration.IgnoreSectionHandler" /> </configSections> <appSettings>  <!-- To enable internal log4net logging specify the following appSettings key -->  <!-- <add key="log4net.Internal.Debug" value="true"/> --> </appSettings> <!-- This section contains the log4net configuration settings --> <log4net>  <!-- Define some output appenders -->  <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">   <param name="File" value="log.txt" />   <param name="AppendToFile" value="true" />   <param name="MaxSizeRollBackups" value="2" />   <param name="MaximumFileSize" value="100KB" />   <param name="RollingStyle" value="Size" />   <param name="StaticLogFileName" value="true" />   <layout type="log4net.Layout.PatternLayout">    <param name="Header" value="[Header]\r\n" />    <param name="Footer" value="[Footer]\r\n" />    <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" />   </layout>  </appender>    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">   <layout type="log4net.Layout.PatternLayout">    <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] &lt;%X{auth}&gt; - %m%n" />   </layout>  </appender>  <!-- Set root logger level to ERROR and its appenders -->  <root>   <level value="ERROR" />   <appender-ref ref="RollingLogFileAppender" />   <appender-ref ref="ConsoleAppender" />  </root>  <!-- Print only messages of level DEBUG or above in the packages -->  <logger name="IBatisNet.DataMapper.Configuration.Cache.CacheModel">   <level value="DEBUG" />  </logger>  <logger name="IBatisNet.DataMapper.Configuration.Statements.PreparedStatementFactory">   <level value="DEBUG" />  </logger>  <logger name="IBatisNet.DataMapper.LazyLoadList">   <level value="DEBUG" />  </logger> </log4net></configuration>

如果我们想要记录所有准备SQL命令的文本,启用日志记录器”IBatisNet.DataMapper.Configuration.Statements.PreparedStatementFactory”。

如果我们想日志缓存的使用,使日志记录器”IBatisNet.DataMapper.Configuration.Cache.CacheModel”。

如果我们想日志lazyload用法,启用日志记录器”IBatisNet.DataMapper.LazyLoadList”。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 12306退票支付宝失败怎么办 12306重复支付怎么办支付宝 支付宝登的12306账号怎么办 没买儿童高铁票怎么办 网上订的机票怎么办托运 半夜买高铁票不出票怎么办 轻轨少买了一站怎么办 高铁火车票丢了怎么办 如果高铁票丢了怎么办 高铁票丢了怎么办 报销 高铁如果没赶上怎么办 高铁管家待核验怎么办 动车没有票了怎么办 12306取消订单3次怎么办 【12306取消订单3次怎么办】 火车票取消订单3次怎么办 12306收不到验证码怎么办 安逸花验证码次数限制怎么办 航班晚点导致错过转机怎么办 想去沈阳站送站怎么办 高铁没有赶上车怎么办 火车晚点赶不上下一趟车怎么办 列车晚点影响下一趟车怎么办? 高铁晚点赶不上下班车怎么办 火车在半路坏了怎么办 做火车中途坏了怎么办 员工怀孕不上班保险怎么办 怀孕带孩子不能上班保险怎么办 怀孕了不想上班保险怎么办 高铁票没票了怎么办 购买动车票无座怎么办 个税工资多报怎么办 火车晚点耽误了转车怎么办 坐火车联系不上怎么办 号码被别人注册了12306怎么办 注册12306的号码换了怎么办 12306号码被注册了怎么办 12306身份证被注册了怎么办 12306被别人注册了怎么办 铁路1236注册名忘记了怎么办 12306手机被别人注册了怎么办