iBatis2學習筆記:基本原理和配置php
iBatis2是一個輕量級的數據持久化框架,它是一個半自動化的ORMapping工具,數據庫的操做依賴程序員本身書寫的SQL,所以能夠最大限度發揮JDBC的性能。據測試,它的性能和JDBC是一個級別的,但代碼比JDBC簡單的多,聽說相對JDBC節省了60%的代碼量。html
缺點是映射不靈活,有時候感受很彆扭。當領域對象關係複雜的時候,關聯基本上行不通。java
iBatis2整個框架的jar包就一個,337KB,相比Hibernate等其餘框架很是的小巧可愛,而且有.net語言版本。mysql
iBatis2的優缺點不是關心的重點,主要是在實際中揚長避短。下面是iBatis2的框架圖:程序員
和Hibernate的SessionFactory相似,iBatis2有SqlMapClientBuilder一個類,經過配置文件SqlMapConfig.xml類構建,這個是線程安全的類,而且是單例模式,從它裏面能夠獲取SqlMapClient,SqlMapClient至關於Hibernate的session,用來執行預約義的SQL語句。sql
所以SqlMapClientBuilder、SqlMapConfig.xml、SqlMapClient將是學習iBatis2的核心。之後會逐漸展開,下面是從變成角度來構建SqlMapClientBuilder。數據庫
String resource ="SqlMapConfig.xml";
Reader reader = Resources.getResourceAsReader(resource);
SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);apache
因爲SqlMapClientBuilder的構建是至關耗時的,所以通常都是在程序啓動的時候構建一次,並反覆使用。安全
SqlMapClient 是線程不安全的,每次用的時候,須要從SqlMapClientBuilder去申請一個。它至關於一個數據庫鏈接。session
下面給出一個我學習的例子,也是iBatis中自帶的一個例子,可是這個例子沒法正常運行,主要是數據庫、驅動還有模糊的配置概念致使。下面詳細講述如何規範的把這個例子跑起來:
環境:
MySQL五、Java五、iBatis2.3
1、下載iBatis:[url]http://ibatis.apache.org/javadownloads.cgi[/url];
下載MySQL5和MySQL5的JDBC驅動:[url]http://dev.mysql.com/downloads/mysql/5.0.html[/url],[url]http://dev.mysql.com/downloads/connector/j/5.1.html[/url]
下載SQLyog Enterprise 6.5,這是MySQL的客戶端工具,[url]http://www.fixdown.com/china/Programming/109.htm[/url]
2、安裝MySQL5,下載MySQL5,解壓縮到某一目錄下,而後修改my-small.ini文件以下:
而後安裝並啓動MySQL5服務
安裝MySQL的客戶端工具,SQLyog Enterprise 6.5
3、在Idea8中建立一個Java工程ibatis_stu
引入兩個必須的包,以下圖:
數據庫連接配置文件 jdbc.properties:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ibatisdb
jdbc.username=root
jdbc.password=leizhimin
構件要操做表:
create table ACCOUNT(
ACC_ID bigint not null AUTO_INCREMENT,
ACC_FIRST_NAME varchar(20) default NULL,
ACC_LAST_NAME varchar(30) default NULL,
ACC_EMAIL varchar(30) default NULL,
PRIMARY KEY(ACC_ID)
) ENGINE=MyISAM DEFAULT CHARSET=gbk COMMENT='IBATIS簡單測試'
iBaits的配置文件SqlMapConfig.xml,(爲了使用一些高級特性,增長了命名空間等配置,同時導入了jdbc.properties來協助配置)
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> <sqlMapConfig> <properties resource="jdbc.properties"/> <settings cacheModelsEnabled="true" errorTracingEnabled="true" enhancementEnabled="true" lazyLoadingEnabled="true" maxRequests="32" maxSessions="10" maxTransactions="5" useStatementNamespaces="true"/> <!-- Configure a built-in transaction manager. If you're using an app server, you probably want to use its transaction manager and a managed datasource --> <transactionManager type="JDBC" commitRequired="false"> <dataSource type="SIMPLE"> <property name="JDBC.Driver" value="${jdbc.driver}"/> <property name="JDBC.ConnectionURL" value="${jdbc.url}"/> <property name="JDBC.Username" value="${jdbc.username}"/> <property name="JDBC.Password" value="${jdbc.password}"/> </dataSource> </transactionManager> <!-- List the SQL Map XML files. They can be loaded from the classpath, as they are here (com.domain.data...) --> <sqlMap resource="com/lavasoft/ibatissut/simple/domain/entity/Account.xml"/> <!-- List more here...--> </sqlMapConfig>
嵌入的Account的表與實體映射代碼:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap namespace="Account"> <!-- Use type aliases to avoid typing the full classname every time. --> <typeAlias alias="Account" type="com.lavasoft.ibatissut.simple.domain.entity.Account"/> <!-- Result maps describe the mapping between the columns returned from a query, and the class properties. A result map isn't necessary if the columns (or aliases) match to the properties exactly. --> <resultMap id="AccountResult" class="Account"> <result property="id" column="ACC_ID"/> <result property="firstName" column="ACC_FIRST_NAME"/> <result property="lastName" column="ACC_LAST_NAME"/> <result property="emailAddress" column="ACC_EMAIL"/> </resultMap> <!-- Select with no parameters using the result map for Account class. --> <select id="selectAllAccounts" resultMap="AccountResult"> select * from ACCOUNT </select> <!-- A simpler select example without the result map. Note the aliases to match the properties of the target result class. --> <select id="selectAccountById" parameterClass="int" resultClass="Account"> select ACC_ID as id, ACC_FIRST_NAME as firstName, ACC_LAST_NAME as lastName, ACC_EMAIL as emailAddress from ACCOUNT where ACC_ID = #id# </select> <!-- Insert example, using the Account parameter class --> <insert id="insertAccount" parameterClass="Account"> insert into account(ACC_ID,ACC_FIRST_NAME,ACC_LAST_NAME,ACC_EMAIL) values(NULL, #firstName#, #lastName#, #emailAddress#) </insert> <!-- Update example, using the Account parameter class --> <update id="updateAccount" parameterClass="Account"> update ACCOUNT set ACC_FIRST_NAME = #firstName#, ACC_LAST_NAME = #lastName#, ACC_EMAIL = #emailAddress# where ACC_ID = #id# </update> <!-- Delete example, using an integer as the parameter class --> <delete id="deleteAccountById" parameterClass="int"> delete from ACCOUNT where ACC_ID = #id# </delete> </sqlMap>
一個與表對應的實體Bean(爲了輸出重寫了toString方法):
package com.lavasoft.ibatissut.simple.domain.entity; /** * Created by IntelliJ IDEA.<p> * User: leizhimin<p> * Date: 2008-8-16 9:57:03<p> * 賬戶 */ public class Account { private int id; private String firstName; private String lastName; private String emailAddress; public Account() { } public Account(String firstName, String lastName, String emailAddress) { this.firstName = firstName; this.lastName = lastName; this.emailAddress = emailAddress; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmailAddress() { return emailAddress; } public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; } @Override public String toString() { return "Account{" + "id=" + id + ", firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", emailAddress='" + emailAddress + '\'' + '}'; } }
核心測試代碼(尊重iBatis的原版風格,就窩下蛋,寫個main方法就開始跑了。。):
package com.lavasoft.ibatissut.simple; import com.ibatis.sqlmap.client.SqlMapClient; import com.ibatis.sqlmap.client.SqlMapClientBuilder; import com.ibatis.common.resources.Resources; import com.lavasoft.ibatissut.simple.domain.entity.Account; import java.io.Reader; import java.io.IOException; import java.util.List; import java.sql.SQLException; /** * Created by IntelliJ IDEA.<p> * User: leizhimin<p> * Date: 2008-8-16 9:59:10<p> * 首先聲明這不是最好的例子,可是從這個例子中能夠很快的瞭解iBatis的工做原理, * 若是須要更好的學習iBatis,能夠參看iBatis實現的JPetStore-5.0.zip。 * [url]http://apache.mirror.phpchina.com/ibatis/binaries/ibatis.java/JPetStore-5.0.zip[/url] */ public class SimpleExample { /** * SqlMapClient的實例是線程安全的,所以僅須要一個實例便可,這裏使用了一個靜態單例模式。 */ private static SqlMapClient sqlMapClient; /** * 將SqlMapClient的構件放到此不是好注意,應該放到一個單例模式的工具類中,須要的時候隨時獲取 */ static { try { //讀取SqlMapConfig的資源配置 Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml"); //構件一個SqlMapClient的實例 sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader); //關閉輸入流 reader.close(); } catch (IOException e) { throw new RuntimeException("在構件SqlMapClient實例的時候發生了異常!" + e, e); } } public static List selectAllAccounts() throws SQLException { //返回全部的賬戶 return sqlMapClient.queryForList("Account.selectAllAccounts"); } public static Account selectAccountById(int id) throws SQLException { return (Account) sqlMapClient.queryForObject("Account.selectAccountById", id); } public static void insertAccount(Account account) throws SQLException { sqlMapClient.insert("Account.insertAccount", account); } public static void updateAccount(Account account) throws SQLException { sqlMapClient.update("Account.updateAccount", account); } public static void deleteAccount(int id) throws SQLException { sqlMapClient.delete("Account.deleteAccount", id); } public static void main(String[] args) throws SQLException { Account act = new Account("1","1","1"); act.setId(23); insertAccount(act); List<Account> acclist= selectAllAccounts(); for(Account acc:acclist){ System.out.println(acc); } } }
運行一把看看:
Account{id=1, firstName='45', lastName='45', emailAddress='4554'}
Account{id=2, firstName='234', lastName='234', emailAddress='23423'}
Account{id=3, firstName='1', lastName='1', emailAddress='1'}
Account{id=4, firstName='1', lastName='1', emailAddress='1'}
Account{id=5, firstName='1', lastName='1', emailAddress='1'}
Process finished with exit code 0
呵呵,終於看到效果了。
iBatis是個好東西,可是技巧性很強,只有徹底掌握了iBatis的映射原理和技巧,用起來纔不至於生硬繁瑣重複。上面這個例子是iBatis發佈包中惟一一個例子,並且使用的是一個你們都很陌生的數據庫,而且沒有執行的入口方法,缺少SQL腳本,沒有使用命名空間等等,這個粗糙的例子給不少第一次接觸iBatis的人一個極壞的印象,和一些致命的誤導。
iBatis應用中應該使用命名空間,不使用的話好像除了HelloWorld這樣的簡單例子外,找不到第二個。