搭建IBatis 框架

说明:

相对Hibernate Apache OJB 一站式”ORM 解决方案而言,ibatis 是一种半自动化ORM 实现。所谓半自动,可能理解上有点生涩。纵观目前主流的ORM ,无论Hibernate 还是Apache OJB,都对数据库结构提供了较为完整的封装,提供了从POJO 到数据库表的全套映射机制。程序员往往只需定义好了POJO 到数据库表的映射关系,即可通过Hibernate 或者OJB 提供的方法完成持久层操作。程序员甚至不需要对SQL 的熟练掌握, Hibernate/OJB 会根据制定的存储逻辑,自动生成对应的SQL 并调用JDBC 接口加以执行。大多数情况下( 特别是对新项目,新系统的开发而言),这样的机制无往不利,大有一统天下的势头。但是,在一些特定的环境下,这种一站式的解决方案却未必灵光。在笔者的系统咨询工作过程中,常常遇到以下情况:
1 系统的部分或全部数据来自现有数据库,处于安全考虑,只对开发团队提供几条Select SQL(或存储过程)以获取所需数据,具体的表结构不予公开。

2
开发规范中要求, 所有牵涉到业务逻辑部分的数据库操作,必须在数据库层由存储过程实现(就笔者工作所面向的金融行业而言,工商银行、中国银行、交 通银行,都在开发规范中严格指定)
3
系统数据处理量巨大,性能要求极为苛刻,这往往意味着我们必须通过经过高度优化的SQL 语句(或存储过程)才能达到系统性能设计指标。面对这样的需求,再次举起Hibernate 大刀,却发现刀锋不再锐利,甚至无法使用,奈何?恍惚之际,只好再摸出JDBC 准备拼死一搏……,说得未免有些凄凉,直接使用JDBC 进行数据库操作实际上也是不错的选择,只是拖沓的数据库访问代码,乏味的字段读取操作令人厌烦。半自动化ibatis,却刚好解决了这个问题。这里的半自动化,是相对Hibernate 等提供了全面的数据库封装机制的全自动化”ORM 实现而言,全自动”ORM 实现了POJO 和数据库表之间的映射,以及SQL 的自动生成和执行。而ibatis 的着力点,则在于POJO SQL 之间的映射关系。也就是说,ibatis 并不会为程序员在运行期自动生成SQL 执行。具体的SQL 需要程序员编写,然后通过映射配置文件,将SQL 所需的参数,以及返回的结果字段映射到指定POJO 。使用ibatis 提供的ORM 机制,对业务逻辑实现人员而言,面对的是纯粹的Java 对象,这一层与通过Hibernate 实现ORM 而言基本一致,而对于具体的数据操作,Hibernate 会自动生成SQL 语句,而ibatis 则要求开发者编写具体的SQL 语句。相对Hibernate 全自动”ORM 机制而言,ibatis SQL 开发的工作量和数据库移植性上的让步,为系统设计提供了更大的自由空间。作为全自动”ORM 实现的一种有益补充,ibatis 的出现显得别具意义。  


 

构建ibatis 基础代码


1.ibatis 实例配置


一个典型的配置文件如下(具体配置项目的含义见后):
<?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>

<settings

cacheModelsEnabled="true"

enhancementEnabled="true"

lazyLoadingEnabled="true"

errorTracingEnabled="true"

maxRequests="32"

maxSessions="10"

maxTransactions="5"

useStatementNamespaces="false"

/>

<transactionManager type="JDBC">  

<dataSource type="SIMPLE">

<property name="JDBC.Driver" value="com.p6spy.engine.spy.P6SpyDriver"/>

<property name="JDBC.ConnectionURL" value="jdbc:mysql://localhost/sample"/>

<property name="JDBC.Username" ="user"/>

<property name="JDBC.Password" ="mypass"/>

<property name=value="10"/>

<property name=value="5"/>

<property name=value="120000"/>

<property name="Pool.TimeToWait" ="500"/>

<property name="Pool.PingQuery" ="select 1 from ACCOUNT"/>

<property name="Pool.PingEnabled" ="false"/>

<property name=value="1"/>

<property name=value="1"/>

</dataSource>

</transactionManager>

<sqlMap resource="com/ibatis/sample/User.xml"/> 

</sqlMapConfig>



2. POJO(Plain Ordinary Java Object)
下面是我们用作示例的一个POJO:
public class User implements Serializable {

private Integer id;

private String name;

private Integer sex;

private Set addresses = new HashSet();

 

/** default constructor */

public User() {

}

 

public Integer getId() {

return this.id;   }

public void setId(Integer id) {

this.id = id;

}

 

public String getName() {

return this.name;

}

 

public void setName(String name) {

this.name = name;

}

 

public Integer getSex() {

return this.sex;

}

 

public void setSex(Integer sex) {

this.sex = sex;

}

}

 

3. 映射文件
与Hibernate 不同。因为需要人工编写SQL 代码,ibatis 的映射文件一般采用手动编写(通过Copy/Paste,手工编写映射文件也并没想象中的麻烦)。针对上面POJO 的映射代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "
http://www.ibatis.com/dtd/sql-map-2.dtd">

 

<sqlMap namespace="User">

<typeAlias alias="user" type="com.ibatis.sample.User"/>

 

<select id="getUser" parameterClass="java.lang.String" resultClass="user">

<![CDATA[

select name, sex

from t_user   where name = #name#

]]>

</select>

 

<update id="updateUser" parameterClass="user">

<![CDATA[

UPDATE t_user

SET name=#name#, sex=#sex#

WHERE id = #id#

]]>

</update>

 

<insert id="insertUser" parameterClass="user" >

INSERT INTO t_user ( name, sex)

VALUES ( #name#,#sex# )

</insert>

 

<delete id="deleteUser" parameterClass="java.lang.String">

delete from t_user

where id = #value#

</delete>

</sqlMap>

 

 

从上面的映射文件可以看出,通过<insert>、<delete>、<update>、<select>四个节点,我们分别定义了针对TUser 对象的增删改查操作。在这四个节点中,我们指定了对应的SQL 语句,以update 节点为例:

 

<update id="updateUser" parameterClass="user">

<![CDATA[

UPDATE t_user

SET (   IBATIS Developer’s Guide Version 1.0

name=#name#,

sex=#sex#

)

WHERE id = #id#

]]>

</update>

⑴ ID
指定了操作ID,之后我们可以在代码中通过指定操作id 来执行此节点所定义的操作,如:sqlMap.update("updateUser",user); ID 设定使得在一个配置文件中定义两个同名节点成为可能(两个update 节点,以不同id 区分)
⑵ parameterClass
指定了操作所需的参数类型,此例中update 操作以com.ibatis.sample.User 类型的对象作为参数,目标是将提供的User 实例更新到数据库。parameterClass="user"中,user 为“com.ibatis.sample.User” 类的别名,别名可通过typeAlias 节点指定,如示例配置文件中的:<typeAlias alias="user" type="com.ibatis.sample.User"/>

⑶ <![CDATA[……]]>
通过<![CDATA[……]]>节点,可以避免SQL 中与XML 规范相冲突的字符对XML 映射文件的合法性造成影响。

⑷ 执行更新操作的SQL,这里的SQL 即实际数据库支持的SQL 语句, 将由 ibatis 填入参数后交给数据库执行。
⑸ SQL 中所需的用户名参数,“#name#”在运行期会由传入的user 对象的name 属性填充。
⑹ SQL 中所需的用户性别参数“#sex#”, 将在运行期由传入的user 对象的sex 属性填充。
⑺ SQL 中所需的条件参数“#id#”, 将在运行期由传入的user 对象的id 属性填充。
对于这个示例,ibatis 在运行期会读取id 为“updateUser”的update 节点的SQL 定义,并调用指定的user 对象的对应getter 方法获取属性值,并用此属性值,对SQL 中的参数进行填充后提交数据库执行。


此例对应应用级代码如下,其中演示了的基本使用方法:
String resource ="com/ibatis/sample/SqlMapConfig.xml";
Reader reader;
//ibatis SQLMap

reader = Resources.getResourceAsReader(resource);
XmlSqlMapClientBuilder xmlBuilder = new XmlSqlMapClientBuilder();
SqlMapClient sqlMap = xmlBuilder.buildSqlMap(reader);
//sqlMap系统初始化完毕,开始执行update操作

try
{
sqlMap.startTransaction();
User user = new User();
user.setId(new Integer(1));
user.setName("Erica");
user.setSex(new Integer(1));
sqlMap.update("updateUser",user);
sqlMap.commitTransaction();
finally{
sqlMap.endTransaction();
}

 

注意:不像EJB那样实体(Entity)和数据库的表(Table)只要通过实体管理器(EntityManager)就可以完全控制,ibatis并不是完全的实体和表之间的映射,它只是把sql文在配置文件中写好,并定义一个ID,对数据库的操作通过调用这个ID就可以实现,执行的是sql文,实体的真正用处仅仅是作为输出和输入的参数。这样看来就是一个JDBC的升级版。
其中,SqlMapClient 是ibatis 运作的核心,所有操作均通过SqlMapClient 实例完成。可以看出,对于应用层而言,程序员面对的是传统意义上的数据对象,而非JDBC 中烦杂的ResultSet,这使得上层逻辑开发人员的工作量大大减轻,同时代码更加清晰简洁。数据库操作在映射文件中加以定义,从而将数据存储逻辑从上层逻辑代码中独立出来。而底层数据操作的SQL 可配置化,使得我们可以控制最终的数据操作方式,通过SQL 的优化获得最佳的数据库执行效能,这在依赖SQL 自动生成的“全自动”ORM   ibatis 配置
结合上面示例中的ibatis 配置文件。附件是对配置文件中各节点的说明:

posted @ 2009-02-16 20:39  kelin1314  阅读(1426)  评论(0编辑  收藏  举报