UML软件工程组织

ibatis开发人员指南(二)
作者:紫龙

本篇文章的第一部分将带你走过一系列的“fash Track”,带你浏览一遍SQL maps的简单应用。在walkthrough之后,将有详细的论述。

Fast Track: Preparing to Use SQL Maps

SQL Maps对不好的数据库模型甚至对象模型都有很强的容忍度。尽管如此,还是推荐你使用最佳实践来设计你的的数据库模型和对象模型。通过这样,你将得到更干净的设计和更好的性能。

 最简单的开始就是分析你在做的内容,商业模型是什么样的,表结构是什么样的,它们怎么样互相发生关系。第一个例子,我们就简单的实现一个典型的Persion类。

Person.java
package examples.domain;
//imports implied….
public class Person {
private int id;
private String firstName;
private String lastName;
private Date birthDate;
private double weightInKilograms;
private double heightInMeters;
public int getId () {
return id;
}
public void setId (int id) {
this.id = id;
}
//…let’s assume we have the other getters and setters to save space…
}

现在persion对象怎么映射到数据库?SQL Maps并不约束你必须要一个表一个对象或者多个表一个对象这种映射关系。因为你可以自由使用SQL语句,所以约束很小。在这个例子里,我们使用下面简单的表,实现一个表对象一个对象的映射关系。

Person.sql
CREATE TABLE PERSON(
PER_ID NUMBER (5, 0) NOT NULL,
PER_FIRST_NAME VARCHAR (40) NOT NULL,
PER_LAST_NAME VARCHAR (40) NOT NULL,
PER_BIRTH_DATE DATETIME ,
PER_WEIGHT_KG NUMBER (4, 2) NOT NULL,
PER_HEIGHT_M NUMBER (4, 2) NOT NULL,
PRIMARY KEY (PER_ID)
)

Fast Track: The SQL Map Configuration File

当我们对我们的工作感到很舒适时,最好的开始就是SQL Map的配置文件。这个文件是SQL Map实现的根配置。

配置文件是XML文件,我们用它来配置属性,JDBC DataSources 和 SQL Maps。它给我们一个便利的地方可以集中配置不同的DataSource。这个框架支持iBATIS SimpleDataSource, Jakarta DBCP (Commons),以及其他任何可以通过JNDI context来访问的DataSource。我们在以后将详细讨论这个问题。现在我们用Jakarta DBCP,结构很简单,象上面这个例子,它的配置文件如下。

SqlMapConfigExample.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE sql-map-config
PUBLIC "-//iBATIS.com//DTD SQL Map Config 1.0//EN"
"http://www.ibatis.com/dtd/sql-map-config.dtd">


<!-- Always ensure to use the correct XML header as above! -->

<sql-map-config>

<!-- The properties (name=value) in the file specified here can be used placeholders in this config
file (e.g. “${driver}”. The file is relative to the classpath and is completely optional. -->

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

<!-- These settings control SqlMap configuration details, primarily to do with transaction
management. They are all optional (more detail later in this document). -->

<settings maxExecute="300"
        maxExecutePerConnection="1"
        maxTransactions="10"
        statementCacheSize="75"
        useGlobalTransactions="false"
        useBeansMetaClasses=”true”/>
<!-- Configure a datasource to use with this SQL Map using Jakarta DBCP.
Notice the use of the properties from the above resource -->
<datasource name="basic" default = "true"
factory-class="com.ibatis.db.sqlmap.datasource.DbcpDataSourceFactory">
        <property name="JDBC.Driver" value="${driver}"/>
        <property name="JDBC.ConnectionURL" value="${url}"/>
        <property name="JDBC.Username" value="${username}"/>
        <property name="JDBC.Password" value="${password}"/>
        <property name="Pool.MaximumActiveConnections" value="10"/>
        <property name="Pool.MaximumIdleConnections" value="5"/>
        <property name="Pool.MaximumWait" value="60000"/>
</datasource>

<!-- Identify all SQL Map XML files to be loaded by this SQL map. Notice the paths
are relative to the classpath. For now, we only have one… -->

<sql-map resource="examples/sqlmap/maps/Person.xml" />

</sql-map-config>

SqlMapConfigExample.properties

# This is just a simple properties file that simplifies automated configuration
# of the SQL Maps configuration file (e.g. by Ant builds or continuous
# integration tools for different environments… etc.)
# These values can be used in any property value in the file above (e.g. “${driver}”)
# Using a properties file such as this is completely optional.


driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:oracle1
username=jsmith
password=test

Fast Track: The SQL Map File(s)

    现在我们已经配置好DataSource了,然后就要准备核心配置文件了。我们需要准备一个实际的SQL Map文件来存放SQL语句和以及用作映射的参数对象和结果对象(分别是输入和输出)。

继续我们上面的示例。让我们为Person类和Person表建立映射关系。我们先建立一个标准结构,和一个简单的select说明。

Person.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE sql-map
PUBLIC "-//iBATIS.com//DTD SQL Map 1.0//EN"
"http://www.ibatis.com/dtd/sql-map.dtd">

<sql-map name="Person">

    <mapped-statement name="getPerson" result-class="examples.domain.Person">
        SELECT
        PER_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#
    </mapped-statement>
</sql-map>

上面的示例显示了一个SQL map的一个最简单的组成。它使用了SQL Maps的一个特性,就是自动根据字段名和JAVABean属性(Map的主键)名建立对应关系。#value#象征着一个输入参数,多情况下,使用"value"意味着我们使用一个基本类型 (e.g. Integer; but we’re not limited to this).

因为非常简单,所以使用这种方法有一些限制。首先不能明确指定每个字段的输入类型。没有办法自动加载相关数据(复杂类型),同时有一些性能影响,因为它使用了ResultSetMetaData。通过使用result-map,我们可以克服所有这些限制。但是现在,简单是我们的目标。同是,以后我们可以随便修改成其他方式(不需要修改java代码)。

多数JAVA程序不仅读取数据,还要更改数据。我们已经看到怎样在Map-statement里使用select 了,那Update,delete和Insert是什么样的?一个好消息,跟select没有什么区别。下面我们就完成一个我们的Person Sql Map,包括一系列的statement用来操作和修改数据。

Person.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE sql-map

PUBLIC "-//iBATIS.com//DTD SQL Map 1.0//EN"

"http://www.ibatis.com/dtd/sql-map.dtd">

<sql-map name="Person">

<!-- Use primitive wrapper type (e.g. Integer) as parameter and allow results to

be auto-mapped results to Person object (JavaBean) properties -->

<mapped-statement name="getPerson" result-class="examples.domain.Person">

SELECT

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

</mapped-statement>

<!-- Use Person object (JavaBean) properties as parameters for insert. Each of the

parameters in the #hash# symbols is a JavaBeans property. -->

<mapped-statement name="insertPerson" >

INSERT INTO

PERSON (PER_ID, PER_FIRST_NAME, PER_LAST_NAME,

PER_BIRTH_DATE, PER_WEIGHT_KG, PER_HEIGHT_M)

VALUES (#id#, #firstName#, #lastName#,

#birthDate#, #weightInKilograms#, #heightInMeters#)

</mapped-statement>

<!-- Use Person object (JavaBean) properties as parameters for update. Each of the

parameters in the #hash# symbols is a JavaBeans property. -->

<mapped-statement name="updatePerson" >

UPDATE PERSON

SET (PER_ID = PER_FIRST_NAME = #firstName#,

PER_LAST_NAME = #lastName#, PER_BIRTH_DATE = #birthDate#,

PER_WEIGHT_KG = #weightInKilograms#,

PER_HEIGHT_M = #heightInMeters#)

WHERE PER_ID = #id#

</mapped-statement>

<!-- Use Person object (JavaBean) “id” properties as parameters for delete. Each of the

parameters in the #hash# symbols is a JavaBeans property. -->

<mapped-statement name="deletePerson" >

DELETE PERSON

WHERE PER_ID = #id#

</mapped-statement>

</sql-map>

Fast Track: Programming with the SQL Map Framework

现在我们已经完成了所有的配置和映射,剩下的就是写JAVA代码了。第一步是配置SQL Map。加载我们前面配置好的SQL Map XML文件是很简单的。加载XML以后,就可以在框架里使用资源类。

String resource = “com/ibatis/example/sql-map-config.xml”;
Reader reader = Resources.getResourceAsReader (resource);
SqlMap sqlMap = XmlSqlMapBuilder.buildSqlMap(reader);

SQL Map对象是线程安全的,意味着是长期生存的。对于一个运行的系统来说,你只要配置一次。所以它可以很好的成为一个基类的静态对象(比如,一个BASE Dao类),也许你更喜欢集中配置并成为全局可见,你可以把它包装在你自己的工具类中。比如说:

private MyAppSqlConfig {

private static final SqlMap sqlMap;

static {

try {

String resource = “com/ibatis/example/sql-map-config.xml”;

Reader reader = Resources.getResourceAsReader (resource);

sqlMap = XmlSqlMapBuilder.buildSqlMap(reader);

} catch (Exception e) {

// If you get an error at this point, it matters little what it was. It is going to be

// unrecoverable and we will want the app to blow up good so we are aware of the

// problem. You should always log such errors and re-throw them in such a way that

// you can be made immediately aware of the problem.

e.printStackTrace();

throw new RuntimeException (“Error initializing MyAppSqlConfig class. Cause: ” + e);

}

}

public static getSqlMapInstance () {

return sqlMap;

}

}

从数据库读取对象

 现在SQL Map实例已经完成初始化,并且很容易访问,我们可以使用它了。首先我们用它从数据库中取得一个Person对象。(举例,我们假设数据库中有10条记录,PER_ID分别从是1到10)

为了从数据库中取得一个Person对象,我们需要SQL Map实例,mapped statement的名称以及PER_ID号,让我们读取#5。 


SqlMap sqlMap = MyAppSqlMapConfig.getSqlMapInstance(); // as coded above

Integer personPk = new Integer(5);
Person person = (Person) sqlMap.executeQueryForObject (“getPerson”, personPk);

把对象写到数据库中

 现在我们已经从数据库取得一个对象,让我们修改一些值,我们将修改身高和体重。   


person.setHeightInMeters(1.83); // person as read from the database above
person.setWeightInKilograms(86.36);

sqlMap.executeUpdate(“updatePerson”, person);

如果我们要删除一个对象,也一样的简单。


sqlMap.executeUpdate(“deletePerson”, person);

同样的,新插入一个对象也类似。

Person newPerson = new Person();
newPerson.setId(11); // you would normally get the ID from a sequence or custom table
newPerson.setFirstName(“Clinton”);
newPerson.setLastName(“Begin”);
newPerson.setBirthDate (null);
newPerson.setHeightInMeters(1.83);
newPerson.setWeightInKilograms(86.36);

sqlMap.executeUpdate (“insertPerson”, newPerson);

End of Fast Track(结束语)

This is the end of the quick walkthrough. The next several sections will discuss the features of the
SqlMap framework in more detail.


版权所有:UML软件工程组织