本篇文章的第一部分將帶你走過一系列的“fash Track”,帶你瀏覽一遍SQL maps的簡單應(yīng)用。在walkthrough之后,將有詳細(xì)的論述。
Fast Track: Preparing to Use SQL Maps
SQL Maps對(duì)不好的數(shù)據(jù)庫模型甚至對(duì)象模型都有很強(qiáng)的容忍度。盡管如此,還是推薦你使用最佳實(shí)踐來設(shè)計(jì)你的的數(shù)據(jù)庫模型和對(duì)象模型。通過這樣,你將得到更干凈的設(shè)計(jì)和更好的性能。
?最簡單的開始就是分析你在做的內(nèi)容,商業(yè)模型是什么樣的,表結(jié)構(gòu)是什么樣的,它們?cè)趺礃踊ハ喟l(fā)生關(guān)系。第一個(gè)例子,我們就簡單的實(shí)現(xiàn)一個(gè)典型的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… } |
現(xiàn)在persion對(duì)象怎么映射到數(shù)據(jù)庫?SQL Maps并不約束你必須要一個(gè)表一個(gè)對(duì)象或者多個(gè)表一個(gè)對(duì)象這種映射關(guān)系。因?yàn)槟憧梢宰杂墒褂肧QL語句,所以約束很小。在這個(gè)例子里,我們使用下面簡單的表,實(shí)現(xiàn)一個(gè)表對(duì)象一個(gè)對(duì)象的映射關(guān)系。
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
當(dāng)我們對(duì)我們的工作感到很舒適時(shí),最好的開始就是SQL Map的配置文件。這個(gè)文件是SQL Map實(shí)現(xiàn)的根配置。
配置文件是XML文件,我們用它來配置屬性,JDBC DataSources 和 SQL Maps。它給我們一個(gè)便利的地方可以集中配置不同的DataSource。這個(gè)框架支持iBATIS SimpleDataSource, Jakarta DBCP (Commons),以及其他任何可以通過JNDI context來訪問的DataSource。我們?cè)谝院髮⒃敿?xì)討論這個(gè)問題。現(xiàn)在我們用Jakarta DBCP,結(jié)構(gòu)很簡單,象上面這個(gè)例子,它的配置文件如下。
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)
????現(xiàn)在我們已經(jīng)配置好DataSource了,然后就要準(zhǔn)備核心配置文件了。我們需要準(zhǔn)備一個(gè)實(shí)際的SQL Map文件來存放SQL語句和以及用作映射的參數(shù)對(duì)象和結(jié)果對(duì)象(分別是輸入和輸出)。
繼續(xù)我們上面的示例。讓我們?yōu)镻erson類和Person表建立映射關(guān)系。我們先建立一個(gè)標(biāo)準(zhǔn)結(jié)構(gòu),和一個(gè)簡單的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> |
上面的示例顯示了一個(gè)SQL map的一個(gè)最簡單的組成。它使用了SQL Maps的一個(gè)特性,就是自動(dòng)根據(jù)字段名和JAVABean屬性(Map的主鍵)名建立對(duì)應(yīng)關(guān)系。#value#象征著一個(gè)輸入?yún)?shù),多情況下,使用"value"意味著我們使用一個(gè)基本類型 (e.g. Integer; but we’re not limited to this).
因?yàn)榉浅:唵危允褂眠@種方法有一些限制。首先不能明確指定每個(gè)字段的輸入類型。沒有辦法自動(dòng)加載相關(guān)數(shù)據(jù)(復(fù)雜類型),同時(shí)有一些性能影響,因?yàn)樗褂昧薘esultSetMetaData。通過使用result-map,我們可以克服所有這些限制。但是現(xiàn)在,簡單是我們的目標(biāo)。同是,以后我們可以隨便修改成其他方式(不需要修改java代碼)。
多數(shù)JAVA程序不僅讀取數(shù)據(jù),還要更改數(shù)據(jù)。我們已經(jīng)看到怎樣在Map-statement里使用select 了,那Update,delete和Insert是什么樣的?一個(gè)好消息,跟select沒有什么區(qū)別。下面我們就完成一個(gè)我們的Person Sql Map,包括一系列的statement用來操作和修改數(shù)據(jù)。
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
現(xiàn)在我們已經(jīng)完成了所有的配置和映射,剩下的就是寫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對(duì)象是線程安全的,意味著是長期生存的。對(duì)于一個(gè)運(yùn)行的系統(tǒng)來說,你只要配置一次。所以它可以很好的成為一個(gè)基類的靜態(tài)對(duì)象(比如,一個(gè)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;
}
}
|
從數(shù)據(jù)庫讀取對(duì)象
?現(xiàn)在SQL Map實(shí)例已經(jīng)完成初始化,并且很容易訪問,我們可以使用它了。首先我們用它從數(shù)據(jù)庫中取得一個(gè)Person對(duì)象。(舉例,我們假設(shè)數(shù)據(jù)庫中有10條記錄,PER_ID分別從是1到10)
為了從數(shù)據(jù)庫中取得一個(gè)Person對(duì)象,我們需要SQL Map實(shí)例,mapped statement的名稱以及PER_ID號(hào),讓我們讀取#5。
… SqlMap sqlMap = MyAppSqlMapConfig.getSqlMapInstance(); // as coded above … Integer personPk = new Integer(5); Person person = (Person) sqlMap.executeQueryForObject (“getPerson”, personPk); … |
把對(duì)象寫到數(shù)據(jù)庫中
?現(xiàn)在我們已經(jīng)從數(shù)據(jù)庫取得一個(gè)對(duì)象,讓我們修改一些值,我們將修改身高和體重。???
… person.setHeightInMeters(1.83); // person as read from the database above person.setWeightInKilograms(86.36); … sqlMap.executeUpdate(“updatePerson”, person); … |
如果我們要?jiǎng)h除一個(gè)對(duì)象,也一樣的簡單。
… sqlMap.executeUpdate(“deletePerson”, person); … |
同樣的,新插入一個(gè)對(duì)象也類似。
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(結(jié)束語)
This is the end of the quick walkthrough. The next several sections will discuss the features of the SqlMap framework in more detail.
|