本篇文章的第一部分將帶你走過一系列的“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.
|