iBatis的簡(jiǎn)單增刪改查操作非常容易掌握,下面我們來(lái)看看iBatis的詳細(xì)配置。雖然iBatis小巧靈活,但是其可擴(kuò)展性也非常強(qiáng)。iBatis的核心配置文件就是SqlMapConfig.xml了,下面我們來(lái)看看iBatis的核心配置結(jié)構(gòu)。
SqlMapConfig配置文件在前面我們知道要配置JDBC連接,SqlMap映射文件等信息,當(dāng)然這都是非?;镜呐渲茫F(xiàn)在我們要探究一下SqlMapConfig的詳細(xì)配置。主要包括以下內(nèi)容:
<properties>元素的配置,它提供了允許在主配置文件之外的一個(gè)“名值對(duì)”列表,可以將其中的配置信息加載進(jìn)來(lái),而這些配置信息可以放在任何一個(gè)地方。使用properties元素,其中有兩個(gè)屬性,分別是:resource和url。
使用resource屬性時(shí),類(lèi)加載器會(huì)從類(lèi)路徑開(kāi)始定位該資源;而使用url屬性時(shí),則是用java.net.URL類(lèi)來(lái)處理的,提供一個(gè)有效的URL即可。之前的示例中,我們使用了resource屬性來(lái)配置數(shù)據(jù)庫(kù)連接信息,如:
<properties resource="jdbc.properties" />
而在jdbc.properties中,我們配置了數(shù)據(jù)庫(kù)的驅(qū)動(dòng)屬性,連接url,用戶(hù)名和密碼,這樣它們就可以被properties元素加載進(jìn)來(lái),使用起來(lái)非常方便。而properties配置文件中是以“名值對(duì)”的方式存儲(chǔ)的,那么我們使用名稱(chēng)即可引用,這是很多人都熟悉的語(yǔ)法,比如:${driver}就能獲取到com.mysql.jdbc.Driver,這里我們使用的是MySQL數(shù)據(jù)庫(kù)。
<settings>元素的配置,這個(gè)元素即設(shè)置iBatis的全局配置信息。下面我們逐一來(lái)看其中可配置的屬性信息。
lazyLoadingEnabled,從名字即可看出是否進(jìn)行延遲加載。通俗來(lái)說(shuō),延遲加載就是只加載必要信息而推遲加載其他未明確請(qǐng)求的數(shù)據(jù),這里要和Hibernate中延遲加載區(qū)分開(kāi)。那也就是說(shuō),除非絕對(duì)必須,否則程序加載的數(shù)據(jù)越少越好。iBatis默認(rèn)使用了延遲加載,即不配置時(shí)也是默認(rèn)為true的。
cacheModelsEnabled,這是數(shù)據(jù)緩存的配置,緩存可以提高程序的性能,這是顯而易見(jiàn)的。和延遲加載一樣,緩存也是默認(rèn)啟用的。
enhancementEnabled,該配置是來(lái)說(shuō)明是否使用cglib中那些優(yōu)化的類(lèi)來(lái)提高延遲加載的性能,默認(rèn)值為true,也就是啟用。但是之前的示例中,并沒(méi)有在lib中加入cglib的類(lèi)庫(kù),那么iBatis沒(méi)有在類(lèi)路徑上發(fā)現(xiàn)cglib時(shí),該功能也就不能起作用了。這里多說(shuō)一點(diǎn),對(duì)于增強(qiáng)框架,除非必須,盡量避免使用。
useStatementNamespaces,該配置說(shuō)明是否使用語(yǔ)句的命名空間,默認(rèn)是不使用的,但是在大型應(yīng)用時(shí),使用命名空間來(lái)作為限定就比較清楚了。使用方法是在<sql-map>標(biāo)記上加namespace屬性即可,在程序中就使用“命名空間.SQL映射語(yǔ)句”這種語(yǔ)法來(lái)執(zhí)行。
settings還可以設(shè)置maxRequests,maxSessions和maxTransactions信息,但它們都已經(jīng)被廢棄了,也就是說(shuō)我們可以不用設(shè)置它們,使用默認(rèn)的就可以了。如果必須要進(jìn)行設(shè)置,那就要保證maxRequests大于maxSessions,而maxSessions要大于maxTransactions。
下面我們來(lái)看<typeAlias>元素,就是起別名,很容易理解,我們不想使用過(guò)長(zhǎng)的類(lèi)名時(shí),可以用它來(lái)起個(gè)別名,之后我們使用別名就可以了。比如:
<typeAlias alias="User" type="ibatis.model.User" />
很容易看出type屬性是原始的類(lèi)名,而alias屬性配置我們希望使用的名字即可。
iBatis已經(jīng)為我們?cè)O(shè)置了一些類(lèi)型的別名,我們就可以直接使用了,比如事務(wù)管理器的JDBC,JTA和EXTERNAL;數(shù)據(jù)類(lèi)型的string,byte,long,short,int等;數(shù)據(jù)源工廠的SIMPLE,DBCP,JNDI;高速緩存控制器的FIFO,LRU,MEMORY,OSCACHE和XML結(jié)果類(lèi)型的DOM,domCollection,Xml,XmlCollection,它們是可以直接使用的。
transactionManager元素,沒(méi)錯(cuò),它就是來(lái)做事務(wù)的。iBatis內(nèi)置的事務(wù)管理器有JDBC,JTA和EXTERNAL。EXTERNAL表示事務(wù)管理器是應(yīng)用程序本身負(fù)責(zé),而不是iBatis。使用type屬性就能在transactionManager元素中配置事務(wù)管理器了。比如:
<transactionManager type="JDBC"></transactionManager>
它還有一個(gè)可以配置的屬性是commitRequired,來(lái)配置在某個(gè)連接釋放之前必須提交或者回滾的情況。
在transactionManager元素中還可以繼續(xù)配置<properties>元素和<dataSource>元素。properties元素用于指定transactionManager的配置項(xiàng),而后者用于配置數(shù)據(jù)源工廠,默認(rèn)提供三種SIMPLE,DBCP和JNDI。
typeHandler元素,即類(lèi)型處理器,用于將數(shù)據(jù)庫(kù)中的數(shù)據(jù)類(lèi)型轉(zhuǎn)換成應(yīng)用程序中使用的數(shù)據(jù)類(lèi)型。假如數(shù)據(jù)庫(kù)中不支持布爾值,那么只能以0/1來(lái)代表,而Java應(yīng)用程序中支持布爾值,這里就需要一個(gè)類(lèi)型處理的過(guò)程。使用時(shí)需要?jiǎng)?chuàng)建兩個(gè)類(lèi),一個(gè)是類(lèi)型處理類(lèi),一個(gè)是類(lèi)型處理回調(diào)類(lèi)。iBatis預(yù)先設(shè)置了大量的類(lèi)型處理器,如果不是必須,為了程序的簡(jiǎn)單,那么盡量不要使用。
最后來(lái)看一下sqlMap元素,它就是配置SQL語(yǔ)句的了,是我們最常用到的一個(gè)標(biāo)簽。可以使用namespace來(lái)確定一個(gè)命名空間,這在之前已經(jīng)說(shuō)到了,可以將同一流程的SQL語(yǔ)句寫(xiě)在一起,放到一個(gè)命名空間下,在程序中使用更加清晰。在sqlMap之中,就是對(duì)數(shù)據(jù)庫(kù)具體操作的實(shí)現(xiàn)了,包括增刪改查等標(biāo)記。
下面是iBatis的配置關(guān)系圖:可以加深對(duì)iBatis的理解。
先說(shuō)點(diǎn)基礎(chǔ)的內(nèi)容,iBatis并不是真正意義上的ORM,官方文檔中稱(chēng)其為dataMapper,是數(shù)據(jù)映射器,也就是一種映射查詢(xún)工具。iBatis不是萬(wàn)能的,在某些它不能處理的問(wèn)題時(shí),不能放棄使用JDBC API,那才是根本中的根本。
在iBatis中,建議使用JavaBean,因?yàn)槲覀兪敲嫦驅(qū)ο蟮脑O(shè)計(jì),那么在系統(tǒng)設(shè)計(jì)時(shí)肯定創(chuàng)建了很多刻畫(huà)具體對(duì)象的類(lèi),使用JavaBean就可以直接操作getter方法來(lái)獲取內(nèi)容。就像是hibernate中的PO一樣。下面來(lái)說(shuō)一種如何獲取Bean中屬性名稱(chēng)和屬性類(lèi)型的方法,這在開(kāi)發(fā)時(shí)可能會(huì)用到。
先定義一個(gè)JavaBean,刻畫(huà)用戶(hù)模型嗎,如下:
package ibatis.model;
public class User implements java.io.Serializable {
private Integer userId;
private String userName;
private String password;
private String mobile;
private String email;
public User() {
super();
}
public User(Integer userId, String userName, String password,
String mobile, String email) {
super();
this.userId = userId;
this.userName = userName;
this.password = password;
this.mobile = mobile;
this.email = email;
}
// 省略getter和setter方法
@Override
public String toString() {
return "User [email=" + email + ", mobile=" + mobile + ", password="
+ password + ", userId=" + userId + ", userName=" + userName
+ "]";
}
}
寫(xiě)一個(gè)方法來(lái)測(cè)試,如下:public static void main(String[] args) {
try {
PropertyDescriptor[] pd = Introspector.getBeanInfo(User.class).getPropertyDescriptors();
for (int i = 0; i < pd.length; i++) {
System.out.println(pd[i].getName() + " ("
+ pd[i].getPropertyType().getName() + ")");
}
} catch (IntrospectionException e) {
e.printStackTrace();
}
}
在控制臺(tái),我們獲得如下輸出:class (java.lang.Class)
email (java.lang.String)
mobile (java.lang.String)
password (java.lang.String)
userId (java.lang.Integer)
userName (java.lang.String)
在定位BUG時(shí),這是很好的一種手段。
接下來(lái),我們來(lái)說(shuō)一下三個(gè)常用的查詢(xún)方法,它們的命名和Spring的JdbcTemplate/SqlMapClientTemplate很像,但是要區(qū)分開(kāi)。
首先是queryForObject()方法,它返回?cái)?shù)據(jù)庫(kù)查詢(xún)的一條結(jié)果,并放入到Java對(duì)象中,這里的一條記錄可以是一個(gè)JavaBean,也可以是Java的集合類(lèi)型。它可以根據(jù)<select>標(biāo)簽中配置的resultClass屬性來(lái)確定的,如果不指定resultClass屬性,那么查詢(xún)結(jié)果就是null了,因?yàn)閕Batis不知道怎么處理這個(gè)結(jié)果,而且我們也沒(méi)有配置結(jié)果映射(resultMap)。
首先我們根據(jù)上面的User類(lèi)型,將resultClass設(shè)置為User,代碼如下:
<sqlMap namespace="User">
<typeAlias alias="User" type="ibatis.model.User" />
<select id="getUserByName" parameterClass="java.lang.String"
resultClass="User">
select *
from users
where USERNAME=#VARCHAR#
</select>
</sqlMap>
這時(shí)要求User類(lèi)中必須要有一個(gè)默認(rèn)的構(gòu)造方法,否則將不能實(shí)例化這個(gè)對(duì)象,拋出異常,這一點(diǎn)不能忘記(如果重載了構(gòu)造方法的話(huà))。我們寫(xiě)一個(gè)程序:System.out
.println(sqlMap.queryForObject("User.getUserByName", "sarin").getClass().getName());
此時(shí),輸出內(nèi)容為:ibatis.model.User,這就很清楚的看到了,查詢(xún)的結(jié)果類(lèi)型是由<select>中的resultClass來(lái)確定的。
queryForObject()的另外一個(gè)重載方法是Object queryForObject(String id, Object parameter, Object resultObject) throws Exception,這種方法是為對(duì)象不能輕易創(chuàng)建的情況使用的(如沒(méi)有默認(rèn)的構(gòu)造方法的對(duì)象),那么使用前面那種格式就會(huì)拋出異常,就需要使用這種方法,看下面代碼:(這里去掉User類(lèi)中的默認(rèn)構(gòu)造方法)
User user=new User(null, null, null, null, null);
user = (User) sqlMap.queryForObject("User.getUserByName", "sarin",
user);
System.out.println(user);
這樣才能獲得user對(duì)象。
第二個(gè)方法是queryForMap()方法,返回結(jié)果可以是一條,也可以是多條。它的方法簽名有兩種形式:第一種是Map queryForMap(String id, Object parameter, String key) throws SQLException,第二種是再多一個(gè)參數(shù)String value。前面兩個(gè)參數(shù)好理解,就是select標(biāo)簽的id和傳入的參數(shù),而后面的key和value是什么意思呢?key指定了Map中存儲(chǔ)的鍵,而value確定了存儲(chǔ)的值,不設(shè)置value時(shí)則存儲(chǔ)查詢(xún)的一個(gè)對(duì)象,如下面代碼(此時(shí)已經(jīng)將select的resultClass設(shè)置為hashmap了):
Map map = sqlMap.queryForMap("User.getAllUsers", null,"userId");
System.out.println(map);
正如你所想,這段代碼的輸出為: {1={email=gmail@gmail.com, userId=1, userName=sarin, password=123, mobile=15940912345}, 2={email=gmail@gmail.com, userId=2, userName=sarin, password=123, mobile=15940912345}}
這里的1和2就是key,是鍵,那么它們是什么類(lèi)型的呢?我們使用如下代碼來(lái)看看: System.out.println(map.keySet().iterator().next().getClass());
得到結(jié)果:class java.lang.Integer,說(shuō)明這是字段相對(duì)應(yīng)的,因?yàn)檫@里我們沒(méi)有將查詢(xún)結(jié)果和JavaBean相關(guān)聯(lián)。那么HashMap中存儲(chǔ)的value是什么類(lèi)型呢?我們來(lái)看,代碼如下:System.out.println(map.get(1).getClass());
打印得到:class java.util.HashMap,說(shuō)明存儲(chǔ)的還是HashMap。而queryForMap()的第二個(gè)重載方法則是指定了value的內(nèi)容,我們來(lái)看: Map map = sqlMap.queryForMap("User.getAllUsers", null, "userId",
"mobile");
System.out.println(map);
這將打?。簕1=15940912345, 2=15940912345},這回就清楚了吧,而且得到的mobile的類(lèi)型是String,也就容易理解了。記住一點(diǎn),queryForMap()方法返回的可以是一條也可以是多條記錄。但是在實(shí)踐中往往用它來(lái)獲取一條完整的記錄,那么使用Map的get()方法就能獲取到其中的值了,非常方便。
下面來(lái)看queryForList()方法,同樣,該方法的方法簽名也有兩類(lèi)形式:第一類(lèi)是queryForList(String id, Object parameter) throws SQLException,或者不需要參數(shù),這很好理解了??磦€(gè)例子:(SqlMap中的resultClass設(shè)置為hashmap)
List users = sqlMap.queryForList("User.getAllUsers");
System.out.println(users);
打印的結(jié)果是:[{email=gmail@gmail.com, userId=1, userName=sarin, password=123, mobile=15940912345}, {email=gmail@gmail.com, userId=2, userName=sarin, password=123, mobile=15940912345}]
就是List中裝入的是HashMap對(duì)象,在SqlMap中將hashmap換為User,那么得到:[User [email=gmail@gmail.com, mobile=15940912345, password=123, userId=1, userName=nanlei], User [email=gmail@gmail.com, mobile=15940912345, password=123, userId=2, userName=sarin]]
queryForList()的第二類(lèi)方法是queryForList(String id, Object parameter, int skip, int max) throws SQLException,可以看出后面多了兩個(gè)int類(lèi)型的參數(shù),那么SQL中使用兩個(gè)int類(lèi)型的參數(shù)能干什么?分頁(yè),沒(méi)錯(cuò),這是主要應(yīng)用。iBatis在queryForList()中提供了為分頁(yè)提供支持的方法。記著skip是從0開(kāi)始計(jì)算的,而max就是取出的條數(shù),那么取前10條就是(0,10),取11~20條就是(10,10),以此類(lèi)推。
更多建議: