代码改变世界

iBATIS In Action:执行非查询语句(一)

2007-11-05 18:52  Anders Cui  阅读(5629)  评论(4编辑  收藏  举报

本章内容包括

  • iBATIS API的更多内容
  • 插入数据
  • 更新和删除数据
  • 使用存储过程

对数据库执行查询无疑很重要,但多数程序同时也需要将数据写入数据库。在本章中,我们将探究使用iBATIS操作数据库的几种方式。本章的内容以第4章介绍的概念为基础,因此,如果您刚开始接触iBATiS,还没读过第4章,可以先去浏览一下,因为这一章中的关于参数映射的绝大部分内容同样适用于本章的非查询语句。

5.1 更新数据的基石 

在第4章中,您已经学习了所有的语句类型和基本查询相关的部分API。这里我们再来看一下执行非查询语句常用的API,然后回顾一下更新数据库相关的语句类型。

5.1.1 非查询SQL语句相关的API

我们把更新数据库的一些“高级”的技术保留在下章中,这里就仅仅看一下insertupdatedelete的基本内容——更新数据库时最常用的三个方法。不过,现在只给出简单的介绍,暂时已经够用了,它们的详细内容将在本章稍后给出。

Insert方法

也许您已猜到,Insert方法用于执行那些对应于SQLINSERT语句的映射语句:

object Insert(string statementName, object parameterObject);

Insert
方法接受两个参数:映射语句的名称(id)和作为参数的对象,后者包含了要插入到数据库的数据。

在更新数据库所用的三个方法中,Insert方法与另两个不同,它返回的是一个object(见5.2.3节)。

Update方法

Update方法用于执行那些对应于SQLUPDATE语句的映射语句:

int Update(string statementName, object parameterObject);

Insert方法一样,Update方法也接受两个参数:映射语句的名称(id)和作为参数的对象。返回值则是执行UPDATE语句所影响的行数。

Delete方法

Delete方法与Update方法几乎一样,只是它是用来执行DELETE语句的:

int Delete(string statementName, object parameterObject);

Delete方法的两个参数与上面两个方法的参数一样:映射语句的名称(id)和作为参数的对象。它的返回值则是DELETE语句所影响的行数。

5.1.2
非查询语句

5.14的表4.1的子集。

语句类型

特性

子元素

用途

详细内容参考

<insert>

id parameterClass parameterMap

所有动态元素<selectKey> <generate>

插入数据

5.2节;
8

<update>

id
parameterClass parameterMap extends

所有动态元素

更新数据

5.3节;
8

<delete>

id
parameterClass parameterMap extends

所有动态元素

删除数据

5.3节;
8

<procedure>

id
parameterMap resultClass resultMap cacheModel

所有动态元素

执行存储过程

5.5节;
8

<statement>

id parameterClass resultClass listClass parameterMap resultMap cacheModel

所有动态元素

可以包含任意类型的语句,几乎无所不能

6.3.1节;
8

译注:在iBATIS.NETDataMapper1.6.1版本中,还有另外两个与语句相关的元素:<sql><include>,能给我们带来更多方便,详细内容请参看iBATIS官方文档。

5.2 插入数据

向数据库中插入数据与查询数据不尽相同,但过程却很相似。不管我们使用的是内联参数还是外部参数映射(这两种参数方式都在第4章有详细描述),在执行任何映射语句时它们的工作原理都是类似的。

5.2.1 使用内联参数

使用内联参数,创建映射语句的过程会很快。这里时一个使用内联参数的<insert>类型语句的例子:

<insert id="insertWithInlineInfo">
    insert into account (
    accountId,
    username, password,
    memberSince,
    firstName, lastName,
    address1, address2,
    city, state, postalCode,
    country, version) 
    values (
    #accountId:NUMBER#,
    #username:VARCHAR#, #password:VARCHAR#,
    #memberSince:TIMESTAMP#,
    #firstName:VARCHAR#, #lastName:VARCHAR#,
    #address1:VARCHAR#, #address2:VARCHAR#,
    #city:VARCHAR#, #state:VARCHAR#, #postalCode:VARCHAR#,
    #country:VARCHAR#, #version:NUMBER#
    )
</insert>

这是映射语句,执行它的代码(在单元测试中)则可以这么写:

Account account = new Account();
account.AccountId 
= 9999;
account.Username 
= "inlineins";
account.Password 
= "poohbear";
account.FirstName 
= "Inline";
account.LastName 
= "Example";
SqlMapper.Insert(
"Account.insertWithInlineInfo", account);

这种方式确实有效,但是一旦程序中包含了<insert><update>语句的多个版本,代码就变得冗长而且难以维护。如果不幸发生了这种情况,那么外部参数就可以帮我们简化SQL Map文件的维护工作了。

5.2.2 使用外部参数

外部参数不仅可以提供内联参数的功能,还能改善性能并在加载时提供更多的校验(这意味着运行时的更少错误)。

这里时一个使用外部参数的<insert>语句示例,其代码在功能上与上个例子一样。

<parameterMap id="fullParameterMapExample" class="Account">
    
<parameter property="accountId" dbType="NUMBER" />
    
<parameter property="username" dbType="VARCHAR" />
    
<parameter property="password" dbType="VARCHAR" />
    
<parameter property="memberSince" dbType="TIMESTAMP" />
    
<parameter property="firstName" dbType="VARCHAR" />
    
<parameter property="lastName" dbType="VARCHAR" />
    
<parameter property="address1" dbType="VARCHAR" />
    
<parameter property="address2" dbType="VARCHAR" />
    
<parameter property="city" dbType="VARCHAR" />
    
<parameter property="state" dbType="VARCHAR" />
    
<parameter property="postalCode" dbType="VARCHAR" />
    
<parameter property="country" dbType="VARCHAR" />
    
<parameter property="version" dbType="NUMBER" />
</parameterMap>
        
<insert id="insertWithExternalInfo"
parameterMap
="fullParameterMapExample">
    insert into account (
    accountId,
    username, password,
    memberSince
    firstName, lastName,
    address1, address2,
    city, state, postalCode,
    country, version) 
    values (?,?,?,?,?,?,?,?,?,?,?,?,?)
</insert>

可是看起来并没简单多少啊!不过如果语句多了,差别就明显了。不仅更为简单(因为不再需要为每个属性指定类型),而且因为有了统一的维护点,如果要修改
Parameter Map,只要修改一处即可。

例如,在传入memberSince的每个地方,iBATIS都会自动将其作为TIMESTAMP数据库类型来处理。过了一段时间,我们觉得DATETIME就够了,只要修改一处——Parameter Map

在前面的两个例子中,执行语句的代码是一样的(除了语句的名称):

sqlMap.Insert("Account.insertWithInlineInfo", account);
sqlMap.Insert(
"Account.insertWithExternalInfo", account);

到这里我们可以看到,内联参数和外部参数的区别在于可维护性和性能——外部参数对此都进行了优化。

5.2.3 自动生成的主键

对于任何数据库来说,提供唯一标识数据表中一行记录的能力是至关重要的。几乎所有数据库都提供了为新添加的行自动生成主键的方法。这样再操作数据库的时候比较方便,但它也带来了一个问题,如果我们需要知道新生成的主键值该怎么办?

有的数据库供应商是预先生成(pre-generate)主键的(如OraclePostgreSQL),有的则是事后生成(post-generate)的(如SQL ServerMySQL)。不管是哪种方式,我们都可以使用<selectKey>节点来获取<insert>语句所产生的主键。下面的例子演示了这两种方式下的做法:

<!-- Oracle SEQUENCE Example using .NET 1.1 System.Data.OracleClient -->
<insert id="insertProduct-ORACLE" parameterClass="product">
    
<selectKey resultClass="int" type="pre" property="Id" >
        SELECT STOCKIDSEQUENCE.NEXTVAL AS VALUE 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" type="post" property="id" >
        select @@IDENTITY as value
    
</selectKey>
</insert>

<!-- MySQL Example -->
<insert id="insertProduct-MYSQL" parameterClass="product">
    insert into PRODUCT (PRD_DESCRIPTION)
    values (#description#)
    
<selectKey resultClass="int" type="post" property="id" >
        select LAST_INSERT_ID() as value
    
</selectKey>
</insert>

上一篇:iBATIS In Action:使用映射语句(二)
下一篇:iBATIS In Action:执行非查询语句(二)